- Added the ability to compile executable binaries for php using gcc

- Refactored execution unit system to use a new execution pointer system
 - Refactored `PhpRunner` to use the new execution pointer system
 - Refactored `BashRunner` to use the new execution pointer system
 - Refactored `LuaRunner` to use the new execution pointer system
 - Refactored `PerlRunner` to use the new execution pointer system
 - Refactored `PythonRunner` to use the new execution pointer system
 - Removed dependency `theseer\Autoload` in favor of ncc's own autoloader (screw you Arne Blankerts)
 - Refactored ZiProto
 - Removed runners `Python2` & `Python3` in favor of `Python`
This commit is contained in:
Netkas 2023-09-10 22:47:24 -04:00
parent ab32a3bba3
commit de88a4fb9e
No known key found for this signature in database
GPG key ID: 5DAF58535614062B
123 changed files with 4370 additions and 7266 deletions

1
.idea/php.xml generated
View file

@ -12,6 +12,7 @@
<component name="PhpIncludePathManager"> <component name="PhpIncludePathManager">
<include_path> <include_path>
<path value="/usr/share/php" /> <path value="/usr/share/php" />
<path value="$PROJECT_DIR$/../focuscrawler/src" />
</include_path> </include_path>
</component> </component>
<component name="PhpProjectSharedConfiguration" php_language_level="8.2"> <component name="PhpProjectSharedConfiguration" php_language_level="8.2">

View file

@ -28,6 +28,7 @@ features and reduced the number of exceptions down to 15 exceptions.
- Added new template PhpCliTemplate `phpcli` - Added new template PhpCliTemplate `phpcli`
- Added new template PhpLibraryTemplate `phplib` - Added new template PhpLibraryTemplate `phplib`
- Added the ability to clean arrays in `\ncc\Utilities > Functions > cleanArray()` - Added the ability to clean arrays in `\ncc\Utilities > Functions > cleanArray()`
- Added the ability to compile executable binaries for php using `gcc`
### Fixed ### Fixed
- Fixed MITM attack vector in `\ncc\Classes > HttpClient > prepareCurl()` - Fixed MITM attack vector in `\ncc\Classes > HttpClient > prepareCurl()`
@ -227,6 +228,12 @@ features and reduced the number of exceptions down to 15 exceptions.
going to list them all here, but you can find them in the commit history. going to list them all here, but you can find them in the commit history.
- Implemented a template engine and refactored the CLI menu for the Project Manager and added a new `template` command - Implemented a template engine and refactored the CLI menu for the Project Manager and added a new `template` command
- Refactored the entire package structure to ncc package structure 2.0 for memory efficiency and performance - Refactored the entire package structure to ncc package structure 2.0 for memory efficiency and performance
- Refactored execution unit system to use a new execution pointer system
- Refactored `PhpRunner` to use the new execution pointer system
- Refactored `BashRunner` to use the new execution pointer system
- Refactored `LuaRunner` to use the new execution pointer system
- Refactored `PerlRunner` to use the new execution pointer system
- Refactored `PythonRunner` to use the new execution pointer system
### Removed ### Removed
@ -290,6 +297,9 @@ features and reduced the number of exceptions down to 15 exceptions.
- Removed unused `\ncc\Objects > NccUpdateInformation` - Removed unused `\ncc\Objects > NccUpdateInformation`
- Removed unused `\ncc\Objects > PhpConfiguration` - Removed unused `\ncc\Objects > PhpConfiguration`
- Removed parameter `$throw_exception` from `\ncc\Objects\ProjectConfiguration > Project > validate()` - Removed parameter `$throw_exception` from `\ncc\Objects\ProjectConfiguration > Project > validate()`
- Removed dependency `theseer\Autoload` in favor of ncc's own autoloader (screw you Arne Blankerts)
- Refactored ZiProto
- Removed runners `Python2` & `Python3` in favor of `Python`

View file

@ -19,7 +19,6 @@ AUTOLOAD_PATHS := $(addprefix $(SRC_PATH)/ncc/ThirdParty/, \
Symfony/Uid \ Symfony/Uid \
Symfony/Filesystem \ Symfony/Filesystem \
Symfony/Yaml \ Symfony/Yaml \
theseer/Autoload \
theseer/DirectoryScanner \ theseer/DirectoryScanner \
) )

View file

@ -26,7 +26,6 @@
$third_party_path . 'Symfony' . DIRECTORY_SEPARATOR . 'Uid' . DIRECTORY_SEPARATOR . 'autoload_spl.php', $third_party_path . 'Symfony' . DIRECTORY_SEPARATOR . 'Uid' . DIRECTORY_SEPARATOR . 'autoload_spl.php',
$third_party_path . 'Symfony' . DIRECTORY_SEPARATOR . 'Filesystem' . DIRECTORY_SEPARATOR . 'autoload_spl.php', $third_party_path . 'Symfony' . DIRECTORY_SEPARATOR . 'Filesystem' . DIRECTORY_SEPARATOR . 'autoload_spl.php',
$third_party_path . 'Symfony' . DIRECTORY_SEPARATOR . 'Yaml' . DIRECTORY_SEPARATOR . 'autoload_spl.php', $third_party_path . 'Symfony' . DIRECTORY_SEPARATOR . 'Yaml' . DIRECTORY_SEPARATOR . 'autoload_spl.php',
$third_party_path . 'theseer' . DIRECTORY_SEPARATOR . 'Autoload' . DIRECTORY_SEPARATOR . 'autoload_spl.php',
$third_party_path . 'theseer' . DIRECTORY_SEPARATOR . 'DirectoryScanner' . DIRECTORY_SEPARATOR . 'autoload_spl.php', $third_party_path . 'theseer' . DIRECTORY_SEPARATOR . 'DirectoryScanner' . DIRECTORY_SEPARATOR . 'autoload_spl.php',
]; ];

View file

@ -0,0 +1,31 @@
<?xml version="1.0"?>
<!--
~ Copyright (c) Nosial 2022-2023, all rights reserved.
~
~ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
~ associated documentation files (the "Software"), to deal in the Software without restriction, including without
~ limitation the rights 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:
~
~ The above copyright notice and this permission notice shall be included in all copies or substantial portions
~ of the Software.
~
~ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
~ INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
~ PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
~ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
~ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
~ DEALINGS IN THE SOFTWARE.
~
-->
<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info">
<mime-type type="application/ncc-package">
<comment>ncc package binary</comment>
<magic priority="50">
<match type="string" value="ncc_pkg" offset="0"/>
</magic>
<glob pattern="*.ncc_pkg"/>
</mime-type>
</mime-info>

View file

@ -1,15 +1,11 @@
<?php <?php
use ncc\Abstracts\Versions; use ncc\Classes\Runtime;
use ncc\Exceptions\ConstantReadonlyException; use ncc\Enums\Versions;
use ncc\Exceptions\ImportException; use ncc\Exceptions\ConfigurationException;
use ncc\Exceptions\InvalidConstantNameException; use ncc\Exceptions\ImportException;
use ncc\Exceptions\InvalidPackageNameException; use ncc\Exceptions\IOException;
use ncc\Exceptions\InvalidScopeException;
use ncc\Exceptions\PackageLockException;
use ncc\Exceptions\PackageNotFoundException;
use ncc\ncc; use ncc\ncc;
use ncc\Runtime;
if(!defined('NCC_INIT')) if(!defined('NCC_INIT'))
{ {
@ -17,26 +13,45 @@
{ {
throw new RuntimeException('Cannot locate file \'%ncc_install' . DIRECTORY_SEPARATOR . 'autoload.php\''); throw new RuntimeException('Cannot locate file \'%ncc_install' . DIRECTORY_SEPARATOR . 'autoload.php\'');
} }
else
{
require('%ncc_install' . DIRECTORY_SEPARATOR . 'autoload.php');
}
require('%ncc_install' . DIRECTORY_SEPARATOR . 'autoload.php');
if(!function_exists('import')) if(!function_exists('import'))
{ {
/** /**
* Attempts to import a package into the current runtime * Attempts to import a package into the current runtime, returns the imported package name
* *
* @param string $package * @param string $package
* @param string $version * @param string $version
* @param array $options * @param array $options
* @return void * @return string
* @throws ImportException
*/ */
function import(string $package, string $version= Versions::Latest, array $options=[]): void function import(string $package, string $version=Versions::LATEST, array $options=[]): string
{ {
Runtime::import($package, $version, $options); try
{
return Runtime::import($package, $version, $options);
}
catch(Exception $e)
{
throw new RuntimeException(sprintf('Unable to import package \'%s\': %s', $package, $e->getMessage()), $e->getCode(), $e);
}
}
}
if(!function_exists('execute'))
{
/**
* Executes the main execution point of an imported package and returns the evaluated result
* This method may exit the program without returning a value
*
* @param string $package
* @return mixed
* @throws ConfigurationException
*/
function execute(string $package): mixed
{
return Runtime::execute($package);
} }
} }
@ -59,112 +74,10 @@
* Returns an array of constants defined by NCC * Returns an array of constants defined by NCC
* *
* @return array * @return array
* @throws \ncc\Exceptions\RuntimeException
*/ */
function ncc_constants(): array function ncc_constants(): array
{ {
return ncc::getConstants(); return ncc::getConstants();
} }
} }
if(!function_exists('consts_get'))
{
/**
* Returns the value of a constant defined in NCC's runtime environment
*
* @param string $package
* @param string $name
* @return string|null
*/
function consts_get(string $package, string $name): ?string
{
return Runtime\Constants::get($package, $name);
}
}
if(!function_exists('consts_set'))
{
/**
* Sets the value of a constant defined in NCC's runtime environment
*
* @param string $package
* @param string $name
* @param string $value
* @param bool $readonly
* @return void
* @throws ConstantReadonlyException
* @throws InvalidConstantNameException
*/
function consts_set(string $package, string $name, string $value, bool $readonly=false): void
{
Runtime\Constants::register($package, $name, $value, $readonly);
}
}
if(!function_exists('consts_delete'))
{
/**
* Deletes a constant defined in NCC's runtime environment
*
* @param string $package
* @param string $name
* @return void
* @throws ConstantReadonlyException
*/
function consts_delete(string $package, string $name): void
{
Runtime\Constants::delete($package, $name);
}
}
if(!function_exists('get_data_path'))
{
/**
* Returns the data path of the package
*
* @param string $package
* @return string
* @throws InvalidPackageNameException
* @throws InvalidScopeException
* @throws PackageLockException
* @throws PackageNotFoundException
*/
function get_data_path(string $package): string
{
return Runtime::getDataPath($package);
}
}
if(!function_exists('get_constant'))
{
/**
* Returns the value of a constant defined in NCC's runtime environment
*
* @param string $package
* @param string $name
* @return string|null
*/
function get_constant(string $package, string $name): ?string
{
return Runtime::getConstant($package, $name);
}
}
if(!function_exists('set_constant'))
{
/**
* Sets the value of a constant defined in NCC's runtime environment
*
* @param string $package
* @param string $name
* @param string $value
* @return void
* @throws ConstantReadonlyException
* @throws InvalidConstantNameException
*/
function set_constant(string $package, string $name, string $value): void
{
Runtime::setConstant($package, $name, $value);
}
}
} }

View file

@ -12,9 +12,7 @@
// Start script // Start script
function scanContents($dir, &$results = array()) function scanContents($dir, &$results = array())
{ {
$files = scandir($dir); foreach (scandir($dir, SCANDIR_SORT_NONE) as $key => $value)
foreach ($files as $key => $value)
{ {
$path = realpath($dir . DIRECTORY_SEPARATOR . $value); $path = realpath($dir . DIRECTORY_SEPARATOR . $value);
if (!is_dir($path)) if (!is_dir($path))
@ -49,6 +47,6 @@
} }
} }
file_put_contents(__DIR__ . DIRECTORY_SEPARATOR . 'checksum.bin', \ncc\ZiProto\ZiProto::encode($hash_values)); file_put_contents(__DIR__ . DIRECTORY_SEPARATOR . 'checksum.bin', \ncc\Extensions\ZiProto\ZiProto::encode($hash_values));
ncc\Utilities\Console::out('Created checksum.bin'); ncc\Utilities\Console::out('Created checksum.bin');
exit(0); exit(0);

View file

@ -31,7 +31,7 @@
use ncc\Utilities\PathFinder; use ncc\Utilities\PathFinder;
use ncc\Utilities\Resolver; use ncc\Utilities\Resolver;
use ncc\Utilities\Validate; use ncc\Utilities\Validate;
use ncc\ZiProto\ZiProto; use ncc\Extensions\ZiProto\ZiProto;
# Global Variables # Global Variables
$NCC_INSTALL_PATH=DIRECTORY_SEPARATOR . 'etc' . DIRECTORY_SEPARATOR . 'ncc'; $NCC_INSTALL_PATH=DIRECTORY_SEPARATOR . 'etc' . DIRECTORY_SEPARATOR . 'ncc';

View file

@ -1,30 +1,29 @@
<?php <?php
/* /*
* Copyright (c) Nosial 2022-2023, all rights reserved. * Copyright (c) Nosial 2022-2023, all rights reserved.
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, including without * associated documentation files (the "Software"), to deal in the Software without restriction, including without
* limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the * limitation the rights 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 * Software, and to permit persons to whom the Software is furnished to do so, subject to the following
* conditions: * conditions:
* *
* The above copyright notice and this permission notice shall be included in all copies or substantial portions * The above copyright notice and this permission notice shall be included in all copies or substantial portions
* of the Software. * of the Software.
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE. * DEALINGS IN THE SOFTWARE.
* *
*/ */
namespace ncc\CLI\Commands; namespace ncc\CLI\Commands;
use Exception; use Exception;
use ncc\Managers\ExecutionPointerManager; use ncc\Classes\Runtime;
use ncc\Managers\PackageLockManager;
use ncc\Objects\CliHelpSection; use ncc\Objects\CliHelpSection;
use ncc\Utilities\Console; use ncc\Utilities\Console;
use ncc\Utilities\Functions; use ncc\Utilities\Functions;
@ -41,8 +40,6 @@ namespace ncc\CLI\Commands;
{ {
$package = $args['package'] ?? null; $package = $args['package'] ?? null;
$version = $args['exec-version'] ?? 'latest'; $version = $args['exec-version'] ?? 'latest';
$unit_name = $args['exec-unit'] ?? 'main';
$set_args = $args['exec-args'] ?? null;
if($package == null) if($package == null)
{ {
@ -50,67 +47,23 @@ namespace ncc\CLI\Commands;
exit(0); exit(0);
} }
$package_lock_manager = new PackageLockManager();
$execution_pointer_manager = new ExecutionPointerManager();
try try
{ {
$package_entry = $package_lock_manager->getPackageLock()->getPackage($package); $package_name = Runtime::import($package, $version);
} }
catch(Exception $e) catch(Exception $e)
{ {
Console::outException('Package ' . $package . ' is not installed', $e, 1); Console::outException('Cannot import package ' . $package, $e, 1);
return;
}
if($package_entry === null)
{
Console::outError('Package ' . $package . ' is not installed', true, 1);
return; return;
} }
try try
{ {
$version_entry = $package_entry->getVersion($version, true); exit(Runtime::execute($package_name));
} }
catch(Exception $e) catch(Exception $e)
{ {
Console::outException('Version ' . $version . ' is not installed', $e, 1); Console::outException($e->getMessage(), $e, 1);
return;
}
try
{
$units = $execution_pointer_manager->getUnits($package_entry->getName(), $version_entry->getVersion());
}
catch(Exception $e)
{
Console::outException(sprintf('Cannot load execution units for package \'%s\'', $package), $e, 1);
return;
}
if(!in_array($unit_name, $units))
{
Console::outError(sprintf('Unit \'%s\' is not configured for package \'%s\'', $unit_name, $package), true, 1);
return;
}
$options = [];
if($set_args != null)
{
global $argv;
$args_index = array_search('--exec-args', $argv);
$options = array_slice($argv, $args_index + 1);
}
try
{
exit($execution_pointer_manager->executeUnit($package_entry->getName(), $version_entry->getVersion(), $unit_name, $options));
}
catch(Exception $e)
{
Console::outException(sprintf('Cannot execute execution point \'%s\' in package \'%s\'', $unit_name, $package), $e, 1);
return; return;
} }
} }
@ -126,7 +79,6 @@ namespace ncc\CLI\Commands;
new CliHelpSection(['help'], 'Displays this help menu about the value command'), new CliHelpSection(['help'], 'Displays this help menu about the value command'),
new CliHelpSection(['exec', '--package'], '(Required) The package to execute'), new CliHelpSection(['exec', '--package'], '(Required) The package to execute'),
new CliHelpSection(['--exec-version'], '(default: latest) The version of the package to execute'), new CliHelpSection(['--exec-version'], '(default: latest) The version of the package to execute'),
new CliHelpSection(['--exec-unit'], '(default: main) The unit point of the package to execute'),
new CliHelpSection(['--exec-args'], '(optional) Anything past this point will be passed to the execution unit'), new CliHelpSection(['--exec-args'], '(optional) Anything past this point will be passed to the execution unit'),
]; ];
@ -144,7 +96,6 @@ namespace ncc\CLI\Commands;
Console::out(PHP_EOL . 'Example Usage:' . PHP_EOL); Console::out(PHP_EOL . 'Example Usage:' . PHP_EOL);
Console::out(' ncc exec --package com.example.program'); Console::out(' ncc exec --package com.example.program');
Console::out(' ncc exec --package com.example.program --exec-version 1.0.0'); Console::out(' ncc exec --package com.example.program --exec-version 1.0.0');
Console::out(' ncc exec --package com.example.program --exec-version 1.0.0 --exec-unit setup');
Console::out(' ncc exec --package com.example.program --exec-args --foo --bar --extra=test'); Console::out(' ncc exec --package com.example.program --exec-args --foo --bar --extra=test');
} }
} }

View file

@ -29,7 +29,7 @@
use ncc\Enums\Scopes; use ncc\Enums\Scopes;
use ncc\Exceptions\IOException; use ncc\Exceptions\IOException;
use ncc\Managers\CredentialManager; use ncc\Managers\CredentialManager;
use ncc\Managers\PackageManager; use ncc\Managers\PackageManagerOld;
use ncc\Objects\CliHelpSection; use ncc\Objects\CliHelpSection;
use ncc\Objects\Package; use ncc\Objects\Package;
use ncc\Objects\RemotePackageInput; use ncc\Objects\RemotePackageInput;
@ -277,7 +277,7 @@
*/ */
private static function getInstallPackages($args): void private static function getInstallPackages($args): void
{ {
$package_manager = new PackageManager(); $package_manager = new PackageManagerOld();
try try
{ {
@ -339,7 +339,7 @@
private static function installPackage($args): void private static function installPackage($args): void
{ {
$package = ($args['package'] ?? $args['p']); $package = ($args['package'] ?? $args['p']);
$package_manager = new PackageManager(); $package_manager = new PackageManagerOld();
if(Resolver::resolveScope() !== Scopes::SYSTEM) if(Resolver::resolveScope() !== Scopes::SYSTEM)
{ {
@ -618,7 +618,7 @@
Console::outError('Missing argument \'package\'', true, 1); Console::outError('Missing argument \'package\'', true, 1);
} }
$package_manager = new PackageManager(); $package_manager = new PackageManagerOld();
try try
{ {
@ -707,7 +707,7 @@
return; return;
} }
$package_manager = new PackageManager(); $package_manager = new PackageManagerOld();
foreach($package_manager->getInstalledPackages() as $package => $versions) foreach($package_manager->getInstalledPackages() as $package => $versions)
{ {

View file

@ -1,59 +1,72 @@
<?php <?php
/* /*
* Copyright (c) Nosial 2022-2023, all rights reserved. * Copyright (c) Nosial 2022-2023, all rights reserved.
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, including without * associated documentation files (the "Software"), to deal in the Software without restriction, including without
* limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the * limitation the rights 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 * Software, and to permit persons to whom the Software is furnished to do so, subject to the following
* conditions: * conditions:
* *
* The above copyright notice and this permission notice shall be included in all copies or substantial portions * The above copyright notice and this permission notice shall be included in all copies or substantial portions
* of the Software. * of the Software.
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE. * DEALINGS IN THE SOFTWARE.
* *
*/ */
namespace ncc\Classes\BashExtension; namespace ncc\Classes\BashExtension;
use ncc\Exceptions\PathNotFoundException; use Exception;
use InvalidArgumentException;
use ncc\Classes\ExecutionUnitRunner;
use ncc\Enums\Runners;
use ncc\Exceptions\IOException;
use ncc\Exceptions\NotSupportedException;
use ncc\Exceptions\OperationException;
use ncc\Interfaces\RunnerInterface; use ncc\Interfaces\RunnerInterface;
use ncc\Objects\Package\ExecutionUnit; use ncc\Objects\Package\ExecutionUnit;
use ncc\Objects\ProjectConfiguration\ExecutionPolicy; use ncc\ThirdParty\Symfony\Process\ExecutableFinder;
use ncc\Utilities\IO; use ncc\Utilities\IO;
use ncc\Utilities\PathFinder;
class BashRunner implements RunnerInterface class BashRunner implements RunnerInterface
{ {
/** /**
* @inheritDoc * @inheritDoc
* @throws PathNotFoundException * @throws IOException
* @throws OperationException
*/ */
public static function processUnit(string $path, ExecutionPolicy $policy): ExecutionUnit public static function executeUnit(ExecutionUnit $unit, array $args=[], bool $local=true): int
{ {
if(!file_exists($path) && !is_file($path)) $tmp = PathFinder::getCachePath() . DIRECTORY_SEPARATOR . hash('sha1', $unit->getData()) . '.bash';
IO::fwrite($tmp, $unit->getData(), 0777);
try
{ {
throw new PathNotFoundException($path); $process = ExecutionUnitRunner::constructProcess($unit, array_merge([$tmp], $args));
$process->run(static function($type, $buffer) use ($unit)
{
if(!$unit->getExecutionPolicy()->getExecute()->isSilent())
{
print($buffer);
}
});
}
catch(Exception $e)
{
throw new OperationException(sprintf('There was an error executing the bash execution unit %s: %s', $unit->getExecutionPolicy()->getName(), $e->getMessage()), $e);
}
finally
{
unlink($tmp);
} }
$execution_unit = new ExecutionUnit(); return $process->getExitCode();
$execution_unit->setExecutionPolicy($policy);
$execution_unit->setData(IO::fread($path));
return $execution_unit;
}
/**
* @inheritDoc
*/
public static function getFileExtension(): string
{
return '.bash';
} }
} }

View file

@ -0,0 +1,151 @@
<?php
/** @noinspection PhpMissingFieldTypeInspection */
/*
* Copyright (c) Nosial 2022-2023, all rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, including without
* limitation the rights 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:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
namespace ncc\Classes;
use Exception;
use ncc\Classes\BashExtension\BashRunner;
use ncc\Classes\NccExtension\ConstantCompiler;
use ncc\Classes\PhpExtension\PhpRunner;
use ncc\Enums\Runners;
use ncc\Exceptions\ConfigurationException;
use ncc\Exceptions\IOException;
use ncc\Exceptions\NotSupportedException;
use ncc\Exceptions\OperationException;
use ncc\Extensions\ZiProto\ZiProto;
use ncc\Objects\Package\ExecutionUnit;
use ncc\ThirdParty\Symfony\Process\ExecutableFinder;
use ncc\ThirdParty\Symfony\Process\Process;
use ncc\Utilities\IO;
class ExecutionUnitRunner
{
/**
* Constructs and returns a process object based off the Execution Unit
*
* @param ExecutionUnit $unit
* @param array $args
* @return Process
* @throws NotSupportedException
*/
public static function constructProcess(ExecutionUnit $unit, array $args=[]): Process
{
$bin = match($unit->getExecutionPolicy()->getRunner())
{
Runners::PHP => (new ExecutableFinder())->find('php'),
Runners::BASH => (new ExecutableFinder())->find('bash'),
Runners::PYTHON => (new ExecutableFinder())->find('python'),
Runners::LUA => (new ExecutableFinder())->find('lua'),
Runners::PERL => (new ExecutableFinder())->find('perl'),
default => throw new NotSupportedException(sprintf('The execution policy %s is not supported because it uses the %s runner', $unit->getExecutionPolicy()->getName(), $unit->getExecutionPolicy()->getRunner()))
};
$process = new Process(array_merge([$bin], $args, $unit->getExecutionPolicy()->getExecute()->getOptions()));
$process->setWorkingDirectory(ConstantCompiler::compileRuntimeConstants($unit->getExecutionPolicy()->getExecute()->getWorkingDirectory()));
$process->setEnv($unit->getExecutionPolicy()->getExecute()->getEnvironmentVariables());
if($unit->getExecutionPolicy()->getExecute()->isTty())
{
$process->setTty(true);
}
if($unit->getExecutionPolicy()->getExecute()->getTimeout() !== null)
{
$process->setTimeout($unit->getExecutionPolicy()->getExecute()->getTimeout());
}
if($unit->getExecutionPolicy()->getExecute()->getIdleTimeout() !== null)
{
$process->setIdleTimeout($unit->getExecutionPolicy()->getExecute()->getIdleTimeout());
}
return $process;
}
/**
* Executes a ExecutionUnit locally on the system
*
* @param string $package_path
* @param string $policy_name
* @param array $args
* @return int
* @throws IOException
* @throws OperationException
*/
public static function executeFromSystem(string $package_path, string $policy_name, array $args=[]): int
{
$unit_path = $package_path . DIRECTORY_SEPARATOR . 'units' . DIRECTORY_SEPARATOR . $policy_name . '.unit';
if(!is_file($unit_path))
{
throw new IOException(sprintf('The execution policy %s does not exist in the package %s (%s)', $policy_name, $package_path, $unit_path));
}
try
{
$execution_unit = ExecutionUnit::fromArray(ZiProto::decode(IO::fread($unit_path)));
return match ($execution_unit->getExecutionPolicy()->getRunner())
{
Runners::PHP => PhpRunner::executeUnit($execution_unit, $args),
Runners::BASH => BashRunner::executeUnit($execution_unit, $args),
default => throw new NotSupportedException(sprintf('The execution policy %s is not supported because it uses the %s runner', $execution_unit->getExecutionPolicy()->getName(), $execution_unit->getExecutionPolicy()->getRunner())),
};
}
catch(Exception $e)
{
throw new OperationException(sprintf('There was an error executing the execution policy %s: %s', $policy_name, $e->getMessage()), $e);
}
}
/**
* Executes the execution policy directly from a package (if supported)
*
* @param PackageReader $package_reader
* @param string $policy_name
* @param array $args
* @return int
* @throws ConfigurationException
* @throws OperationException
*/
public static function executeFromPackage(PackageReader $package_reader, string $policy_name, array $args=[]): int
{
$execution_unit = $package_reader->getExecutionUnit($policy_name);
try
{
return match ($execution_unit->getExecutionPolicy()->getRunner())
{
Runners::PHP => PhpRunner::executeUnit($execution_unit, $args, false),
Runners::BASH => BashRunner::executeUnit($execution_unit, $args),
default => throw new NotSupportedException(sprintf('The execution policy %s is not supported because it uses the %s runner', $execution_unit->getExecutionPolicy()->getName(), $execution_unit->getExecutionPolicy()->getRunner())),
};
}
catch(Exception $e)
{
throw new OperationException(sprintf('There was an error executing the execution policy from a package %s: %s', $policy_name, $e->getMessage()), $e);
}
}
}

View file

@ -1,54 +1,74 @@
<?php <?php
/* /*
* Copyright (c) Nosial 2022-2023, all rights reserved. * Copyright (c) Nosial 2022-2023, all rights reserved.
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, including without * associated documentation files (the "Software"), to deal in the Software without restriction, including without
* limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the * limitation the rights 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 * Software, and to permit persons to whom the Software is furnished to do so, subject to the following
* conditions: * conditions:
* *
* The above copyright notice and this permission notice shall be included in all copies or substantial portions * The above copyright notice and this permission notice shall be included in all copies or substantial portions
* of the Software. * of the Software.
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE. * DEALINGS IN THE SOFTWARE.
* *
*/ */
namespace ncc\Classes\LuaExtension; namespace ncc\Classes\LuaExtension;
use Exception;
use InvalidArgumentException;
use ncc\Classes\ExecutionUnitRunner;
use ncc\Enums\Runners;
use ncc\Exceptions\IOException;
use ncc\Exceptions\NotSupportedException;
use ncc\Exceptions\OperationException;
use ncc\Exceptions\PathNotFoundException; use ncc\Exceptions\PathNotFoundException;
use ncc\Interfaces\RunnerInterface; use ncc\Interfaces\RunnerInterface;
use ncc\Objects\Package\ExecutionUnit; use ncc\Objects\Package\ExecutionUnit;
use ncc\Objects\ProjectConfiguration\ExecutionPolicy; use ncc\Objects\ProjectConfiguration\ExecutionPolicy;
use ncc\ThirdParty\Symfony\Process\ExecutableFinder;
use ncc\Utilities\IO; use ncc\Utilities\IO;
use ncc\Utilities\PathFinder;
class LuaRunner implements RunnerInterface class LuaRunner implements RunnerInterface
{ {
/** /**
* @inheritDoc * @inheritDoc
* @throws PathNotFoundException * @throws OperationException
* @throws IOException
*/ */
public static function processUnit(string $path, ExecutionPolicy $policy): ExecutionUnit public static function executeUnit(ExecutionUnit $unit, array $args=[], bool $local=true): int
{ {
$execution_unit = new ExecutionUnit(); $tmp = PathFinder::getCachePath() . DIRECTORY_SEPARATOR . hash('sha1', $unit->getData()) . '.lua';
$execution_unit->setExecutionPolicy($policy); IO::fwrite($tmp, $unit->getData(), 0777);
$execution_unit->setData(IO::fread($path));
return $execution_unit; try
} {
$process = ExecutionUnitRunner::constructProcess($unit, array_merge([$tmp], $args));
$process->run(static function($type, $buffer) use ($unit)
{
if(!$unit->getExecutionPolicy()->getExecute()->isSilent())
{
print($buffer);
}
});
}
catch(Exception $e)
{
throw new OperationException(sprintf('There was an error executing the lua execution unit %s: %s', $unit->getExecutionPolicy()->getName(), $e->getMessage()), $e);
}
finally
{
unlink($tmp);
}
/** return $process->getExitCode();
* @inheritDoc
*/
public static function getFileExtension(): string
{
return '.lua';
} }
} }

View file

@ -28,22 +28,25 @@
use ncc\Classes\PackageWriter; use ncc\Classes\PackageWriter;
use ncc\CLI\Main; use ncc\CLI\Main;
use ncc\Enums\ComponentDataType; use ncc\Enums\ComponentDataType;
use ncc\Enums\Flags\PackageFlags;
use ncc\Enums\LogLevel; use ncc\Enums\LogLevel;
use ncc\Enums\Options\BuildConfigurationOptions;
use ncc\Enums\Options\BuildConfigurationValues; use ncc\Enums\Options\BuildConfigurationValues;
use ncc\Exceptions\ConfigurationException; use ncc\Exceptions\ConfigurationException;
use ncc\Exceptions\IOException; use ncc\Exceptions\IOException;
use ncc\Exceptions\NotSupportedException; use ncc\Exceptions\NotSupportedException;
use ncc\Exceptions\PathNotFoundException; use ncc\Exceptions\PathNotFoundException;
use ncc\Interfaces\CompilerInterface;
use ncc\Managers\ProjectManager; use ncc\Managers\ProjectManager;
use ncc\Objects\Package; use ncc\Objects\Package;
use ncc\Objects\Package\Resource; use ncc\Objects\ProjectConfiguration\Build\BuildConfiguration;
use ncc\Utilities\Base64; use ncc\Utilities\Base64;
use ncc\Utilities\Console; use ncc\Utilities\Console;
use ncc\Utilities\Functions; use ncc\Utilities\Functions;
use ncc\Utilities\IO; use ncc\Utilities\IO;
use ncc\Utilities\Resolver; use ncc\Utilities\Resolver;
class NccCompiler class NccCompiler implements CompilerInterface
{ {
/** /**
* @var ProjectManager * @var ProjectManager
@ -59,18 +62,35 @@
} }
/** /**
* Returns the project manager
*
* @return ProjectManager
*/
public function getProjectManager(): ProjectManager
{
return $this->project_manager;
}
/**
* @inheritDoc
* @param string $build_configuration * @param string $build_configuration
* @return string * @return string
* @throws ConfigurationException * @throws ConfigurationException
* @throws IOException * @throws IOException
* @throws NotSupportedException * @throws NotSupportedException
* @throws PathNotFoundException * @throws PathNotFoundException
* @noinspection UnusedFunctionResultInspection
*/ */
public function build(string $build_configuration=BuildConfigurationValues::DEFAULT): string public function build(string $build_configuration=BuildConfigurationValues::DEFAULT): string
{ {
$configuration = $this->project_manager->getProjectConfiguration()->getBuild()->getBuildConfiguration($build_configuration); $configuration = $this->project_manager->getProjectConfiguration()->getBuild()->getBuildConfiguration($build_configuration);
$package_path = $configuration->getOutputPath() . DIRECTORY_SEPARATOR . $this->project_manager->getProjectConfiguration()->getAssembly()->getPackage() . '.ncc'; $package_path = $configuration->getOutputPath() . DIRECTORY_SEPARATOR . $this->project_manager->getProjectConfiguration()->getAssembly()->getPackage() . '.ncc';
$package_writer = new PackageWriter($package_path); $progress = 0;
$steps =
count($this->project_manager->getProjectConfiguration()->getExecutionPolicies()) +
count($this->project_manager->getComponents($build_configuration)) +
count($this->project_manager->getResources($build_configuration));
$package_writer = $this->createPackageWriter($package_path, $configuration);
Console::out(sprintf('Building project \'%s\'', $this->project_manager->getProjectConfiguration()->getAssembly()->getName())); Console::out(sprintf('Building project \'%s\'', $this->project_manager->getProjectConfiguration()->getAssembly()->getName()));
@ -89,7 +109,7 @@
} }
Console::outVerbose('Building package header...'); Console::outVerbose('Building package header...');
$package_writer->setMetadata($this->buildMetadata($build_configuration)); $this->processMetadata($package_writer, $build_configuration);
Console::outVerbose('Adding assembly information...'); Console::outVerbose('Adding assembly information...');
$package_writer->setAssembly($this->project_manager->getProjectConfiguration()->getAssembly()); $package_writer->setAssembly($this->project_manager->getProjectConfiguration()->getAssembly());
@ -104,16 +124,20 @@
// Process execution policies // Process execution policies
if(count($this->project_manager->getProjectConfiguration()->getExecutionPolicies()) > 0) if(count($this->project_manager->getProjectConfiguration()->getExecutionPolicies()) > 0)
{ {
Console::out('Processing execution policies...'); Console::outVerbose('Processing execution policies...');
$execution_units = $this->project_manager->getExecutionUnits($build_configuration); $execution_units = $this->project_manager->getExecutionUnits($build_configuration);
if(count($execution_units) === 0) if(count($execution_units) === 0)
{ {
$progress = count($this->project_manager->getProjectConfiguration()->getExecutionPolicies());
Console::inlineProgressBar($progress, $steps);
Console::outWarning('The project contains execution policies but none of them are used'); Console::outWarning('The project contains execution policies but none of them are used');
} }
foreach($execution_units as $unit) foreach($execution_units as $unit)
{ {
$progress++;
Console::inlineProgressBar($progress, $steps);
$package_writer->addExecutionUnit($unit); $package_writer->addExecutionUnit($unit);
} }
} }
@ -121,68 +145,119 @@
// Compile package components // Compile package components
foreach($this->project_manager->getComponents($build_configuration) as $component) foreach($this->project_manager->getComponents($build_configuration) as $component)
{ {
$progress++;
Console::inlineProgressBar($progress, $steps);
Console::outVerbose(sprintf('Compiling \'%s\'', $component)); Console::outVerbose(sprintf('Compiling \'%s\'', $component));
$package_writer->addComponent($this->buildComponent($component));
$this->processComponent($package_writer, $component);
} }
// Compile package resources // Compile package resources
foreach($this->project_manager->getResources($build_configuration) as $resource) foreach($this->project_manager->getResources($build_configuration) as $resource)
{ {
$progress++;
Console::inlineProgressBar($progress, $steps);
Console::outVerbose(sprintf('Processing \'%s\'', $resource)); Console::outVerbose(sprintf('Processing \'%s\'', $resource));
$package_writer->addResource($this->buildResource($resource));
$this->processResource($package_writer, $resource);
} }
$package_writer->close(); $package_writer->close();
return $package_path; return $package_path;
} }
/**
* Creates a package writer with the specified options
*
* @param string $path
* @param BuildConfiguration $build_configuration
* @return PackageWriter
* @throws IOException
* @throws NotSupportedException
*/
private function createPackageWriter(string $path, BuildConfiguration $build_configuration): PackageWriter
{
$package_writer = new PackageWriter($path);
if(isset($build_configuration->getOptions()[BuildConfigurationOptions::COMPRESSION]))
{
$package_writer->addFlag(PackageFlags::COMPRESSION);
switch(strtolower($build_configuration->getOptions()[BuildConfigurationOptions::COMPRESSION]))
{
case BuildConfigurationOptions\CompressionOptions::HIGH:
$package_writer->addFlag(PackageFlags::HIGH_COMPRESSION);
break;
case BuildConfigurationOptions\CompressionOptions::MEDIUM:
$package_writer->addFlag(PackageFlags::MEDIUM_COMPRESSION);
break;
case BuildConfigurationOptions\CompressionOptions::LOW:
$package_writer->addFlag(PackageFlags::LOW_COMPRESSION);
break;
default:
throw new NotSupportedException(sprintf('The compression level \'%s\' is not supported', $build_configuration->getOptions()[BuildConfigurationOptions::COMPRESSION]));
}
}
return $package_writer;
}
/** /**
* Compiles a single component as a base64 encoded string * Compiles a single component as a base64 encoded string
* *
* @param PackageWriter $package_writer
* @param string $file_path * @param string $file_path
* @return Package\Component
* @throws IOException * @throws IOException
* @throws PathNotFoundException * @throws PathNotFoundException
* @noinspection UnusedFunctionResultInspection
*/ */
public function buildComponent(string $file_path): Package\Component public function processComponent(PackageWriter $package_writer, string $file_path): void
{ {
return new Package\Component( $package_writer->addComponent(new Package\Component(
Functions::removeBasename($file_path), Functions::removeBasename($file_path),
Base64::encode(IO::fread($file_path)), ComponentDataType::BASE64_ENCODED Base64::encode(IO::fread($file_path)), ComponentDataType::BASE64_ENCODED
); ));
} }
/** /**
* Packs a resource into the package
*
* @param PackageWriter $package_writer
* @param string $file_path * @param string $file_path
* @return Resource * @return void
* @throws IOException * @throws IOException
* @throws PathNotFoundException * @throws PathNotFoundException
* @noinspection UnusedFunctionResultInspection
*/ */
public function buildResource(string $file_path): Package\Resource public function processResource(PackageWriter $package_writer, string $file_path): void
{ {
return new Package\Resource( $package_writer->addResource(new Package\Resource(
basename($file_path), IO::fread($file_path) Functions::removeBasename($file_path), IO::fread($file_path)
); ));
} }
/** /**
* Builds the package header * Processes the package metadata
* *
* @param ProjectManager $project_manager * @param PackageWriter $package_writer
* @param string $build_configuration * @param string $build_configuration
* @return Package\Metadata * @return void
* @throws ConfigurationException * @throws ConfigurationException
* @throws IOException
* @noinspection UnusedFunctionResultInspection
*/ */
public function buildMetadata(string $build_configuration=BuildConfigurationValues::DEFAULT): Package\Metadata public function processMetadata(PackageWriter $package_writer, string $build_configuration=BuildConfigurationValues::DEFAULT): void
{ {
$header = new Package\Metadata($this->project_manager->getProjectConfiguration()->getProject()->getCompiler()); $metadata = new Package\Metadata($this->project_manager->getProjectConfiguration()->getProject()->getCompiler());
$header->setRuntimeConstants($this->project_manager->getRuntimeConstants($build_configuration)); $metadata->setRuntimeConstants($this->project_manager->getRuntimeConstants($build_configuration));
$header->setOptions($this->project_manager->getCompilerOptions($build_configuration)); $metadata->setOptions($this->project_manager->getCompilerOptions($build_configuration));
$header->setUpdateSource($this->project_manager->getProjectConfiguration()->getProject()->getUpdateSource()); $metadata->setUpdateSource($this->project_manager->getProjectConfiguration()->getProject()->getUpdateSource());
$header->setMainExecutionPolicy($this->project_manager->getProjectConfiguration()->getBuild()->getMain()); $metadata->setMainExecutionPolicy($this->project_manager->getProjectConfiguration()->getBuild()->getMain());
$header->setInstaller($this->project_manager->getProjectConfiguration()->getInstaller()); $metadata->setInstaller($this->project_manager->getProjectConfiguration()->getInstaller());
return $header; $package_writer->setMetadata($metadata);
} }
} }

View file

@ -25,14 +25,18 @@
namespace ncc\Classes; namespace ncc\Classes;
use ncc\Enums\Flags\PackageFlags;
use ncc\Enums\PackageDirectory;
use ncc\Exceptions\ConfigurationException; use ncc\Exceptions\ConfigurationException;
use ncc\Exceptions\IOException; use ncc\Exceptions\IOException;
use ncc\Objects\Package\Component; use ncc\Objects\Package\Component;
use ncc\Objects\Package\ExecutionUnit; use ncc\Objects\Package\ExecutionUnit;
use ncc\Objects\Package\Metadata; use ncc\Objects\Package\Metadata;
use ncc\Objects\Package\Resource;
use ncc\Objects\ProjectConfiguration\Assembly; use ncc\Objects\ProjectConfiguration\Assembly;
use ncc\Objects\ProjectConfiguration\Dependency;
use ncc\Objects\ProjectConfiguration\Installer; use ncc\Objects\ProjectConfiguration\Installer;
use ncc\ZiProto\ZiProto; use ncc\Extensions\ZiProto\ZiProto;
use RuntimeException; use RuntimeException;
use ncc\Enums\PackageStructure; use ncc\Enums\PackageStructure;
@ -53,6 +57,11 @@
*/ */
private $package_file; private $package_file;
/**
* @var array
*/
private $cache;
/** /**
* PackageReader constructor. * PackageReader constructor.
* *
@ -72,18 +81,26 @@
throw new IOException(sprintf('Failed to open file \'%s\'', $file_path)); throw new IOException(sprintf('Failed to open file \'%s\'', $file_path));
} }
$magic_bytes = fread($this->package_file, 7); $pre_header = '';
$header = '';
$diameter_hit = false; $diameter_hit = false;
$this->header_length = 7;
// Check for the magic bytes "ncc_pkg" // Dynamically calculate header length until "ncc_pkg" is found
if($magic_bytes !== 'ncc_pkg') while (!feof($this->package_file))
{ {
throw new IOException(sprintf('File \'%s\' is not a valid package file (invalid magic bytes)', $file_path)); $char = fread($this->package_file, 1);
$pre_header .= $char;
if (str_ends_with($pre_header, 'ncc_pkg'))
{
break;
}
} }
// Calculate header length including "ncc_pkg"
$this->header_length = strlen($pre_header);
// Read everything after "ncc_pkg" up until the delimiter (0x1F 0x1F) // Read everything after "ncc_pkg" up until the delimiter (0x1F 0x1F)
$header = '';
while(!feof($this->package_file)) while(!feof($this->package_file))
{ {
$this->header_length++; $this->header_length++;
@ -109,6 +126,7 @@
} }
$this->headers = ZiProto::decode($header); $this->headers = ZiProto::decode($header);
$this->cache = [];
} }
/** /**
@ -163,7 +181,7 @@
} }
/** /**
* Gets a resource from the package * Returns a resource from the package by name
* *
* @param string $name * @param string $name
* @return string * @return string
@ -177,9 +195,28 @@
$location = explode(':', $this->headers[PackageStructure::DIRECTORY][$name]); $location = explode(':', $this->headers[PackageStructure::DIRECTORY][$name]);
fseek($this->package_file, ($this->header_length + (int)$location[0])); fseek($this->package_file, ($this->header_length + (int)$location[0]));
if(in_array(PackageFlags::COMPRESSION, $this->headers[PackageStructure::FLAGS], true))
{
return gzuncompress(fread($this->package_file, (int)$location[1]));
}
return fread($this->package_file, (int)$location[1]); return fread($this->package_file, (int)$location[1]);
} }
/**
* Returns a resource from the package by pointer
*
* @param int $pointer
* @param int $length
* @return string
*/
public function getByPointer(int $pointer, int $length): string
{
fseek($this->package_file, ($this->header_length + $pointer));
return fread($this->package_file, $length);
}
/** /**
* Returns the package's assembly * Returns the package's assembly
* *
@ -188,12 +225,21 @@
*/ */
public function getAssembly(): Assembly public function getAssembly(): Assembly
{ {
if(!isset($this->headers[PackageStructure::DIRECTORY]['@assembly'])) $directory = sprintf('@%s', PackageDirectory::ASSEMBLY);
if(isset($this->cache[$directory]))
{
return $this->cache[$directory];
}
if(!isset($this->headers[PackageStructure::DIRECTORY][$directory]))
{ {
throw new ConfigurationException('Package does not contain an assembly'); throw new ConfigurationException('Package does not contain an assembly');
} }
return Assembly::fromArray(ZiProto::decode($this->get('@assembly'))); $assembly = Assembly::fromArray(ZiProto::decode($this->get($directory)));
$this->cache[$directory] = $assembly;
return $assembly;
} }
/** /**
@ -204,12 +250,21 @@
*/ */
public function getMetadata(): Metadata public function getMetadata(): Metadata
{ {
if(!isset($this->headers[PackageStructure::DIRECTORY]['@metadata'])) $directory = sprintf('@%s', PackageDirectory::METADATA);
if(isset($this->cache[$directory]))
{
return $this->cache[$directory];
}
if(!isset($this->headers[PackageStructure::DIRECTORY][$directory]))
{ {
throw new ConfigurationException('Package does not contain metadata'); throw new ConfigurationException('Package does not contain metadata');
} }
return Metadata::fromArray(ZiProto::decode($this->get('@metadata'))); $metadata = Metadata::fromArray(ZiProto::decode($this->get($directory)));
$this->cache[$directory] = $metadata;
return $metadata;
} }
/** /**
@ -219,12 +274,21 @@
*/ */
public function getInstaller(): ?Installer public function getInstaller(): ?Installer
{ {
if(!isset($this->headers[PackageStructure::DIRECTORY]['@installer'])) $directory = sprintf('@%s', PackageDirectory::INSTALLER);
if(isset($this->cache[$directory]))
{
return $this->cache[$directory];
}
if(!isset($this->headers[PackageStructure::DIRECTORY][$directory]))
{ {
return null; return null;
} }
return Installer::fromArray(ZiProto::decode($this->get('@installer'))); $installer = Installer::fromArray(ZiProto::decode($this->get($directory)));
$this->cache[$directory] = $installer;
return $installer;
} }
/** /**
@ -235,11 +299,13 @@
public function getDependencies(): array public function getDependencies(): array
{ {
$dependencies = []; $dependencies = [];
$directory = sprintf('@%s:', PackageDirectory::DEPENDENCIES);
foreach($this->headers[PackageStructure::DIRECTORY] as $name => $location) foreach($this->headers[PackageStructure::DIRECTORY] as $name => $location)
{ {
if(str_starts_with($name, '@dependencies:')) if(str_starts_with($name, $directory))
{ {
$dependencies[] = str_replace('@dependencies:', '', $name); $dependencies[] = str_replace($directory, '', $name);
} }
} }
@ -250,18 +316,31 @@
* Returns a dependency from the package * Returns a dependency from the package
* *
* @param string $name * @param string $name
* @return array * @return Dependency
* @throws ConfigurationException * @throws ConfigurationException
*/ */
public function getDependency(string $name): array public function getDependency(string $name): Dependency
{ {
$dependency_name = sprintf('@dependencies:%s', $name); $dependency_name = sprintf('@%s:%s', PackageDirectory::DEPENDENCIES, $name);
if(!isset($this->headers[PackageStructure::DIRECTORY][$dependency_name])) if(!isset($this->headers[PackageStructure::DIRECTORY][$dependency_name]))
{ {
throw new ConfigurationException(sprintf('Dependency \'%s\' not found in package', $name)); throw new ConfigurationException(sprintf('Dependency \'%s\' not found in package', $name));
} }
return ZiProto::decode($this->get('@dependencies:' . $name)); return Dependency::fromArray(ZiProto::decode($this->get($dependency_name)));
}
/**
* Returns a dependency from the package by pointer
*
* @param int $pointer
* @param int $length
* @return Dependency
* @throws ConfigurationException
*/
public function getDependencyByPointer(int $pointer, int $length): Dependency
{
return Dependency::fromArray(ZiProto::decode($this->getByPointer($pointer, $length)));
} }
/** /**
@ -272,11 +351,13 @@
public function getExecutionUnits(): array public function getExecutionUnits(): array
{ {
$execution_units = []; $execution_units = [];
$directory = sprintf('@%s:', PackageDirectory::EXECUTION_UNITS);
foreach($this->headers[PackageStructure::DIRECTORY] as $name => $location) foreach($this->headers[PackageStructure::DIRECTORY] as $name => $location)
{ {
if(str_starts_with($name, '@execution_units:')) if(str_starts_with($name, $directory))
{ {
$execution_units[] = str_replace('@execution_units:', '', $name); $execution_units[] = str_replace($directory, '', $name);
} }
} }
@ -292,7 +373,7 @@
*/ */
public function getExecutionUnit(string $name): ExecutionUnit public function getExecutionUnit(string $name): ExecutionUnit
{ {
$execution_unit_name = sprintf('@execution_units:%s', $name); $execution_unit_name = sprintf('@%s:%s', PackageDirectory::EXECUTION_UNITS, $name);
if(!isset($this->headers[PackageStructure::DIRECTORY][$execution_unit_name])) if(!isset($this->headers[PackageStructure::DIRECTORY][$execution_unit_name]))
{ {
throw new ConfigurationException(sprintf('Execution unit \'%s\' not found in package', $name)); throw new ConfigurationException(sprintf('Execution unit \'%s\' not found in package', $name));
@ -302,24 +383,55 @@
} }
/** /**
* Returns the package's components * Returns an execution unit from the package by pointer
*
* @param int $pointer
* @param int $length
* @return ExecutionUnit
* @throws ConfigurationException
*/
public function getExecutionUnitByPointer(int $pointer, int $length): ExecutionUnit
{
return ExecutionUnit::fromArray(ZiProto::decode($this->getByPointer($pointer, $length)));
}
/**
* Returns the package's component pointers
* *
* @return array * @return array
*/ */
public function getComponents(): array public function getComponents(): array
{ {
$components = []; $components = [];
$directory = sprintf('@%s:', PackageDirectory::COMPONENTS);
foreach($this->headers[PackageStructure::DIRECTORY] as $name => $location) foreach($this->headers[PackageStructure::DIRECTORY] as $name => $location)
{ {
if(str_starts_with($name, '@components:')) if(str_starts_with($name, $directory))
{ {
$components[] = str_replace('@components:', '', $name); $components[] = str_replace($directory, '', $name);
} }
} }
return $components; return $components;
} }
public function getClassMap(): array
{
$class_map = [];
$directory = sprintf('@%s:', PackageDirectory::CLASS_POINTER);
foreach($this->headers[PackageStructure::DIRECTORY] as $name => $location)
{
if(str_starts_with($name, $directory))
{
$class_map[] = str_replace($directory, '', $name);
}
}
return $class_map;
}
/** /**
* Returns a component from the package * Returns a component from the package
* *
@ -329,28 +441,61 @@
*/ */
public function getComponent(string $name): Component public function getComponent(string $name): Component
{ {
$component_name = sprintf('@components:%s', $name); $component_name = sprintf('@%s:%s', PackageDirectory::COMPONENTS, $name);
if(!isset($this->headers[PackageStructure::DIRECTORY][$component_name])) if(!isset($this->headers[PackageStructure::DIRECTORY][$component_name]))
{ {
throw new ConfigurationException(sprintf('Component \'%s\' not found in package', $name)); throw new ConfigurationException(sprintf('Component \'%s\' not found in package', $name));
} }
return Component::fromArray(ZiProto::decode($this->get('@components:' . $name))); return Component::fromArray(ZiProto::decode($this->get($component_name)));
} }
/** /**
* Returns an array of resources from the package * Returns a component from the package by pointer
*
* @param int $pointer
* @param int $length
* @return Component
* @throws ConfigurationException
*/
public function getComponentByPointer(int $pointer, int $length): Component
{
return Component::fromArray(ZiProto::decode($this->getByPointer($pointer, $length)));
}
/**
* Returns a component from the package by a class pointer
*
* @param string $class
* @return Component
* @throws ConfigurationException
*/
public function getComponentByClass(string $class): Component
{
$class_name = sprintf('@%s:%s', PackageDirectory::CLASS_POINTER, $class);
if(!isset($this->headers[PackageStructure::DIRECTORY][$class_name]))
{
throw new ConfigurationException(sprintf('Class map \'%s\' not found in package', $class));
}
return Component::fromArray(ZiProto::decode($this->get($class_name)));
}
/**
* Returns an array of resource pointers from the package
* *
* @return array * @return array
*/ */
public function getResources(): array public function getResources(): array
{ {
$resources = []; $resources = [];
$directory = sprintf('@%s:', PackageDirectory::RESOURCES);
foreach($this->headers[PackageStructure::DIRECTORY] as $name => $location) foreach($this->headers[PackageStructure::DIRECTORY] as $name => $location)
{ {
if(str_starts_with($name, '@resources:')) if(str_starts_with($name, $directory))
{ {
$resources[] = str_replace('@resources:', '', $name); $resources[] = str_replace($directory, '', $name);
} }
} }
@ -361,18 +506,31 @@
* Returns a resource from the package * Returns a resource from the package
* *
* @param string $name * @param string $name
* @return string * @return Resource
* @throws ConfigurationException * @throws ConfigurationException
*/ */
public function getResource(string $name): string public function getResource(string $name): Resource
{ {
$resource_name = sprintf('@resources:%s', $name); $resource_name = sprintf('@%s:%s', PackageDirectory::RESOURCES, $name);
if(!isset($this->headers[PackageStructure::DIRECTORY][$resource_name])) if(!isset($this->headers[PackageStructure::DIRECTORY][$resource_name]))
{ {
throw new ConfigurationException(sprintf('Resource \'%s\' not found in package', $name)); throw new ConfigurationException(sprintf('Resource \'%s\' not found in package', $name));
} }
return $this->get('@resources:' . $name); return Resource::fromArray(ZiProto::decode($this->get($resource_name)));
}
/**
* Returns a resource from the package by pointer
*
* @param int $pointer
* @param int $length
* @return Resource
* @throws ConfigurationException
*/
public function getResourceByPointer(int $pointer, int $length): Resource
{
return Resource::fromArray(ZiProto::decode($this->getByPointer($pointer, $length)));
} }
/** /**

View file

@ -25,6 +25,8 @@
namespace ncc\Classes; namespace ncc\Classes;
use ncc\Enums\Flags\PackageFlags;
use ncc\Enums\PackageDirectory;
use ncc\Enums\PackageStructure; use ncc\Enums\PackageStructure;
use ncc\Enums\PackageStructureVersions; use ncc\Enums\PackageStructureVersions;
use ncc\Exceptions\IOException; use ncc\Exceptions\IOException;
@ -35,7 +37,7 @@
use ncc\Objects\ProjectConfiguration\Assembly; use ncc\Objects\ProjectConfiguration\Assembly;
use ncc\Objects\ProjectConfiguration\Dependency; use ncc\Objects\ProjectConfiguration\Dependency;
use ncc\Objects\ProjectConfiguration\Installer; use ncc\Objects\ProjectConfiguration\Installer;
use ncc\ZiProto\ZiProto; use ncc\Extensions\ZiProto\ZiProto;
class PackageWriter class PackageWriter
{ {
@ -59,6 +61,11 @@
*/ */
private $temporary_path; private $temporary_path;
/**
* @var bool
*/
private $data_written;
/** /**
* PackageWriter constructor. * PackageWriter constructor.
* *
@ -94,6 +101,7 @@
touch($file_path); touch($file_path);
touch($file_path . '.tmp'); touch($file_path . '.tmp');
$this->data_written = false;
$this->temporary_path = $file_path . '.tmp'; $this->temporary_path = $file_path . '.tmp';
$this->temp_file = @fopen($this->temporary_path, 'wb'); // Create a temporary data file $this->temp_file = @fopen($this->temporary_path, 'wb'); // Create a temporary data file
$this->package_file = @fopen($file_path, 'wb'); $this->package_file = @fopen($file_path, 'wb');
@ -148,6 +156,11 @@
*/ */
public function setFlags(array $flags): void public function setFlags(array $flags): void
{ {
if($this->data_written)
{
throw new IOException('Cannot set flags after data has been written to the package');
}
$this->headers[PackageStructure::FLAGS] = $flags; $this->headers[PackageStructure::FLAGS] = $flags;
} }
@ -156,9 +169,15 @@
* *
* @param string $flag * @param string $flag
* @return void * @return void
* @throws IOException
*/ */
public function addFlag(string $flag): void public function addFlag(string $flag): void
{ {
if($this->data_written)
{
throw new IOException('Cannot add a flag after data has been written to the package');
}
if(!in_array($flag, $this->headers[PackageStructure::FLAGS], true)) if(!in_array($flag, $this->headers[PackageStructure::FLAGS], true))
{ {
$this->headers[PackageStructure::FLAGS][] = $flag; $this->headers[PackageStructure::FLAGS][] = $flag;
@ -173,6 +192,11 @@
*/ */
public function removeFlag(string $flag): void public function removeFlag(string $flag): void
{ {
if($this->data_written)
{
throw new IOException('Cannot remove a flag after data has been written to the package');
}
$this->headers[PackageStructure::FLAGS] = array_diff($this->headers[PackageStructure::FLAGS], [$flag]); $this->headers[PackageStructure::FLAGS] = array_diff($this->headers[PackageStructure::FLAGS], [$flag]);
} }
@ -181,102 +205,159 @@
* *
* @param string $name * @param string $name
* @param string $data * @param string $data
* @return void * @return array
* @throws IOException * @throws IOException
*/ */
public function add(string $name, string $data): void public function add(string $name, string $data): array
{ {
if(isset($this->headers[PackageStructure::DIRECTORY][$name])) if(isset($this->headers[PackageStructure::DIRECTORY][$name]))
{ {
throw new IOException(sprintf('Resource \'%s\' already exists in package', $name)); throw new IOException(sprintf('Resource \'%s\' already exists in package', $name));
} }
$this->headers[PackageStructure::DIRECTORY][$name] = sprintf("%d:%d", ftell($this->temp_file), strlen($data)); if(in_array(PackageFlags::COMPRESSION, $this->headers[PackageStructure::FLAGS], true))
{
if(in_array(PackageFlags::LOW_COMPRESSION, $this->headers[PackageStructure::FLAGS], true))
{
$data = gzcompress($data, 1);
}
else if(in_array(PackageFlags::MEDIUM_COMPRESSION, $this->headers[PackageStructure::FLAGS], true))
{
$data = gzcompress($data, 6);
}
else if(in_array(PackageFlags::HIGH_COMPRESSION, $this->headers[PackageStructure::FLAGS], true))
{
$data = gzcompress($data, 9);
}
else
{
$data = gzcompress($data);
}
}
$pointer = sprintf("%d:%d", ftell($this->temp_file), strlen($data));
$this->headers[PackageStructure::DIRECTORY][$name] = $pointer;
$this->data_written = true;
fwrite($this->temp_file, $data); fwrite($this->temp_file, $data);
return explode(':', $pointer);
}
/**
* Adds a pointer to the package
*
* @param string $name
* @param int $offset
* @param int $length
* @return void
* @throws IOException
*/
public function addPointer(string $name, int $offset, int $length): void
{
if(isset($this->headers[PackageStructure::DIRECTORY][$name]))
{
throw new IOException(sprintf('Resource \'%s\' already exists in package', $name));
}
$this->headers[PackageStructure::DIRECTORY][$name] = sprintf("%d:%d", $offset, $length);
} }
/** /**
* Sets the assembly of the package * Sets the assembly of the package
* *
* @param Assembly $assembly * @param Assembly $assembly
* @return void * @return array
* @throws IOException * @throws IOException
*/ */
public function setAssembly(Assembly $assembly): void public function setAssembly(Assembly $assembly): array
{ {
$this->add('@assembly', ZiProto::encode($assembly->toArray())); return $this->add(sprintf('@%s', PackageDirectory::ASSEMBLY), ZiProto::encode($assembly->toArray(true)));
} }
/** /**
* Adds the metadata to the package * Adds the metadata to the package
* *
* @param Metadata $metadata * @param Metadata $metadata
* @return void * @return array
* @throws IOException * @throws IOException
*/ */
public function setMetadata(Metadata $metadata): void public function setMetadata(Metadata $metadata): array
{ {
$this->add('@metadata', ZiProto::encode($metadata->toArray())); return $this->add(sprintf('@%s', PackageDirectory::METADATA), ZiProto::encode($metadata->toArray(true)));
} }
/** /**
* Sets the installer information of the package * Sets the installer information of the package
* *
* @param Installer $installer * @param Installer $installer
* @return void * @return array
* @throws IOException * @throws IOException
*/ */
public function setInstaller(Installer $installer): void public function setInstaller(Installer $installer): array
{ {
$this->add('@installer', ZiProto::encode($installer->toArray())); return $this->add(sprintf('@%s', PackageDirectory::INSTALLER), ZiProto::encode($installer->toArray(true)));
} }
/** /**
* Adds a dependency configuration to the package * Adds a dependency configuration to the package
* *
* @param Dependency $dependency * @param Dependency $dependency
* @return void * @return array
* @throws IOException * @throws IOException
*/ */
public function addDependencyConfiguration(Dependency $dependency): void public function addDependencyConfiguration(Dependency $dependency): array
{ {
$this->add(sprintf('@dependencies:%s', $dependency->getName()), ZiProto::encode($dependency->toArray())); return $this->add(sprintf('@%s:%s', PackageDirectory::DEPENDENCIES, $dependency->getName()), ZiProto::encode($dependency->toArray(true)));
} }
/** /**
* Adds an execution unit to the package * Adds an execution unit to the package
* *
* @param ExecutionUnit $unit * @param ExecutionUnit $unit
* @return void * @return array
* @throws IOException * @throws IOException
*/ */
public function addExecutionUnit(ExecutionUnit $unit): void public function addExecutionUnit(ExecutionUnit $unit): array
{ {
$this->add(sprintf('@execution_units:%s', $unit->getExecutionPolicy()->getName()), ZiProto::encode($unit->toArray())); return $this->add(sprintf('@%s:%s', PackageDirectory::EXECUTION_UNITS, $unit->getExecutionPolicy()->getName()), ZiProto::encode($unit->toArray(true)));
} }
/** /**
* Adds a component to the package * Adds a component to the package
* *
* @param Component $component * @param Component $component
* @return void * @return array
* @throws IOException * @throws IOException
*/ */
public function addComponent(Component $component): void public function addComponent(Component $component): array
{ {
$this->add(sprintf('@components:%s', $component->getName()), ZiProto::encode($component->toArray())); return $this->add(sprintf('@%s:%s', PackageDirectory::COMPONENTS, $component->getName()), ZiProto::encode($component->toArray(true)));
} }
/** /**
* Adds a resource to the package * Adds a resource to the package
* *
* @param Resource $resource * @param Resource $resource
* @return array
* @throws IOException
*/
public function addResource(Resource $resource): array
{
return $this->add(sprintf('@%s:%s', PackageDirectory::RESOURCES, $resource->getName()), $resource->getData());
}
/**
* Maps a class to a component in the package
*
* @param string $class
* @param int $offset
* @param int $length
* @return void * @return void
* @throws IOException * @throws IOException
*/ */
public function addResource(Resource $resource): void public function mapClass(string $class, int $offset, int $length): void
{ {
$this->add(sprintf('@resources:%s', $resource->getName()), $resource->getData()); $this->addPointer(sprintf('@%s:%s', PackageDirectory::CLASS_POINTER, $class), $offset, $length);
} }
/** /**
@ -327,5 +408,17 @@
{ {
// Ignore // Ignore
} }
finally
{
if(is_resource($this->package_file))
{
fclose($this->package_file);
}
if(is_resource($this->temp_file))
{
fclose($this->temp_file);
}
}
} }
} }

View file

@ -22,44 +22,51 @@
namespace ncc\Classes\PerlExtension; namespace ncc\Classes\PerlExtension;
use Exception;
use ncc\Classes\ExecutionUnitRunner;
use ncc\Exceptions\IOException; use ncc\Exceptions\IOException;
use ncc\Exceptions\NotSupportedException;
use ncc\Exceptions\OperationException;
use ncc\Exceptions\PathNotFoundException; use ncc\Exceptions\PathNotFoundException;
use ncc\Interfaces\RunnerInterface; use ncc\Interfaces\RunnerInterface;
use ncc\Objects\Package\ExecutionUnit; use ncc\Objects\Package\ExecutionUnit;
use ncc\Objects\ProjectConfiguration\ExecutionPolicy; use ncc\Objects\ProjectConfiguration\ExecutionPolicy;
use ncc\ThirdParty\Symfony\Process\ExecutableFinder;
use ncc\Utilities\IO; use ncc\Utilities\IO;
use ncc\Utilities\PathFinder;
class PerlRunner implements RunnerInterface class PerlRunner implements RunnerInterface
{ {
/** /**
* @inheritDoc * @inheritDoc
* @param string $path
* @param ExecutionPolicy $policy
* @return ExecutionUnit
* @throws IOException * @throws IOException
* @throws PathNotFoundException * @throws OperationException
*/ */
public static function processUnit(string $path, ExecutionPolicy $policy): ExecutionUnit public static function executeUnit(ExecutionUnit $unit, array $args=[], bool $local=true): int
{ {
$execution_unit = new ExecutionUnit(); $tmp = PathFinder::getCachePath() . DIRECTORY_SEPARATOR . hash('sha1', $unit->getData()) . '.pl';
IO::fwrite($tmp, $unit->getData(), 0777);
if(!file_exists($path) && !is_file($path)) try
{ {
throw new PathNotFoundException($path); $process = ExecutionUnitRunner::constructProcess($unit, array_merge([$tmp], $args));
$process->run(static function($type, $buffer) use ($unit)
{
if(!$unit->getExecutionPolicy()->getExecute()->isSilent())
{
print($buffer);
}
});
}
catch(Exception $e)
{
throw new OperationException(sprintf('There was an error executing the perl execution unit %s: %s', $unit->getExecutionPolicy()->getName(), $e->getMessage()), $e);
}
finally
{
unlink($tmp);
} }
$execution_unit->setExecutionPolicy($policy); return $process->getExitCode();
$execution_unit->setData(IO::fread($path));
return $execution_unit;
}
/**
* @inheritDoc
*/
public static function getFileExtension(): string
{
return '.pl';
} }
} }

View file

@ -0,0 +1,257 @@
<?php
/*
* Copyright (c) Nosial 2022-2023, all rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, including without
* limitation the rights 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:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
namespace ncc\Classes\PhpExtension;
use ncc\ThirdParty\nikic\PhpParser\Comment;
use ncc\ThirdParty\nikic\PhpParser\Node;
use ReflectionClass;
use ReflectionException;
use RuntimeException;
class AstWalker
{
/**
* Returns an array representation of the node recursively
*
* @param array|Node $node
* @return array
*/
public static function serialize(array|Node $node): array
{
if(is_array($node))
{
$serialized = [];
foreach($node as $sub_node)
{
$serialized[] = $sub_node->jsonSerialize();
}
return $serialized;
}
return $node->jsonSerialize();
}
/**
* Returns an array of classes associated with the node recursively
*
* @param Node|array $node
* @param string $prefix
* @return array
*/
public static function extractClasses(Node|array $node, string $prefix=''): array
{
if(is_array($node))
{
$classes = [];
foreach($node as $sub_node)
{
/** @noinspection SlowArrayOperationsInLoopInspection */
$classes = array_merge($classes, self::extractClasses($sub_node, $prefix));
}
return $classes;
}
$classes = [];
if ($node instanceof Node\Stmt\ClassLike)
{
$classes[] = $prefix . $node->name;
}
if ($node instanceof Node\Stmt\Namespace_)
{
if ($node->name && $node->name->parts)
{
$prefix .= implode('\\', $node->name->parts) . '\\';
}
else
{
$prefix = '';
}
}
foreach ($node->getSubNodeNames() as $node_name)
{
if ($node->$node_name instanceof Node)
{
/** @noinspection SlowArrayOperationsInLoopInspection */
$classes = array_merge($classes, self::extractClasses($node->$node_name, $prefix));
}
elseif (is_array($node->$node_name))
{
foreach ($node->$node_name as $sub_node)
{
if ($sub_node instanceof Node)
{
/** @noinspection SlowArrayOperationsInLoopInspection */
$classes = array_merge($classes, self::extractClasses($sub_node, $prefix));
}
}
}
}
return $classes;
}
/**
* Reconstructs nodes from an array representation recursively
*
* @param $value
* @return array|Comment|Node
* @noinspection PhpMissingReturnTypeInspection
* @throws ReflectionException
*/
public static function decodeRecursive($value)
{
if (is_array($value))
{
if (isset($value['nodeType']))
{
if ($value['nodeType'] === 'Comment' || $value['nodeType'] === 'Comment_Doc')
{
return self::decodeComment($value);
}
return self::decodeNode($value);
}
return self::decodeArray($value);
}
return $value;
}
/**
* Decodes an array by recursively decoding each value
*
* @param array $array
* @return array
* @throws ReflectionException
*/
private static function decodeArray(array $array) : array
{
$decoded_array = [];
foreach ($array as $key => $value)
{
$decoded_array[$key] = self::decodeRecursive($value);
}
return $decoded_array;
}
/**
* Returns the node from the node type
*
* @param array $value
* @return Node
* @throws ReflectionException
*/
private static function decodeNode(array $value) : Node
{
$node_type = $value['nodeType'];
if (!is_string($node_type))
{
throw new RuntimeException('Node type must be a string');
}
/** @var Node $node */
$node = self::reflectionClassFromNodeType($node_type)->newInstanceWithoutConstructor();
if (isset($value['attributes'])) {
if (!is_array($value['attributes']))
{
throw new RuntimeException('Attributes must be an array');
}
$node->setAttributes(self::decodeArray($value['attributes']));
}
foreach ($value as $name => $sub_node) {
if ($name === 'nodeType' || $name === 'attributes')
{
continue;
}
$node->$name = self::decodeRecursive($sub_node);
}
return $node;
}
/**
* Returns the comment from the node type
*
* @param array $value
* @return Comment
*/
private static function decodeComment(array $value): Comment
{
$class_name = $value['nodeType'] === 'Comment' ? Comment::class : Comment\Doc::class;
if (!isset($value['text']))
{
throw new RuntimeException('Comment must have text');
}
return new $class_name(
$value['text'],
$value['line'] ?? -1, $value['filePos'] ?? -1, $value['tokenPos'] ?? -1,
$value['endLine'] ?? -1, $value['endFilePos'] ?? -1, $value['endTokenPos'] ?? -1
);
}
/**
* Returns the reflection class from the node type
*
* @param string $node_type
* @return ReflectionClass
* @throws ReflectionException
*/
private static function reflectionClassFromNodeType(string $node_type): ReflectionClass
{
return new ReflectionClass(self::classNameFromNodeType($node_type));
}
/**
* Returns the class name from the node type
*
* @param string $nodeType
* @return string
*/
private static function classNameFromNodeType(string $nodeType): string
{
$class_name = 'ncc\\ThirdParty\\nikic\\PhpParser\\Node\\' . str_replace('_', '\\', $nodeType);
if (class_exists($class_name))
{
return $class_name;
}
$class_name .= '_';
if (class_exists($class_name))
{
return $class_name;
}
throw new RuntimeException("Unknown node type \"$nodeType\"");
}
}

View file

@ -0,0 +1,170 @@
<?php
/*
* Copyright (c) Nosial 2022-2023, all rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, including without
* limitation the rights 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:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
namespace ncc\Classes\PhpExtension;
use ncc\CLI\Main;
use ncc\Enums\LogLevel;
use ncc\Enums\Options\BuildConfigurationValues;
use ncc\Exceptions\BuildException;
use ncc\ThirdParty\Symfony\Process\ExecutableFinder;
use ncc\ThirdParty\Symfony\Process\Process;
use ncc\Utilities\Console;
use ncc\Utilities\Functions;
use ncc\Utilities\PathFinder;
class ExecutableCompiler extends NccCompiler
{
/**
* @inheritDoc
* @throws BuildException
*/
public function build(string $build_configuration = BuildConfigurationValues::DEFAULT): string
{
$configuration = $this->getProjectManager()->getProjectConfiguration()->getBuild()->getBuildConfiguration($build_configuration);
if(!isset($configuration->getOptions()['ncc_configuration']))
{
throw new BuildException(sprintf("Unable to compile the binary, the build configuration '%s' does not have a ncc_configuration.", $build_configuration));
}
// Build the ncc package first
Console::outVerbose('Building ncc package.');
$ncc_package = parent::build($configuration->getOptions()['ncc_configuration']);
// Prepare the ncc package for compilation
$hex_dump_file = PathFinder::getCachePath() . DIRECTORY_SEPARATOR . parent::getProjectManager()->getProjectConfiguration()->getAssembly()->getName() . '.c';
if(is_file($hex_dump_file))
{
unlink($hex_dump_file);
}
Console::outVerbose(sprintf('Converting ncc package %s to hex dump', $ncc_package));
$this->hexDump($ncc_package, $hex_dump_file, parent::getProjectManager()->getProjectConfiguration()->getAssembly()->getName());
// Prepare the gcc command
$gcc_path = (new ExecutableFinder())->find('gcc');
$binary_path = $configuration->getOutputPath() . DIRECTORY_SEPARATOR . parent::getProjectManager()->getProjectConfiguration()->getAssembly()->getName();
if($gcc_path === null)
{
throw new BuildException("Unable to find gcc executable, please make sure it is installed and in your PATH environment variable.");
}
if(!is_file(__DIR__ . DIRECTORY_SEPARATOR . 'bootstrap_main.c'))
{
throw new BuildException("Unable to find bootstrap_main.c, please make sure ncc is installed correctly.");
}
$gcc_options = [
__DIR__ . DIRECTORY_SEPARATOR . 'bootstrap_main.c',
realpath($hex_dump_file)
];
foreach($configuration->getOptions() as $option => $value)
{
if(str_starts_with($option, 'gcc-'))
{
$gcc_options[] = sprintf('-%s%s', substr($option, 4), $value === null ? '' : '=' . $value);
}
}
$gcc_options[] = '-o';
$gcc_options[] = $binary_path;
switch(Main::getLogLevel())
{
case LogLevel::VERBOSE:
$gcc_options[] = '-v';
break;
case LogLevel::DEBUG:
$gcc_options[] = '-v';
$gcc_options[] = '-v';
break;
}
$process = new Process([$gcc_path, ...$gcc_options]);
$process->setTimeout(0);
Console::outVerbose(sprintf('Compiling executable to %s: %s', $binary_path, implode(' ', $gcc_options)));
$process->run(static function ($type, $buffer)
{
Console::outVerbose(rtrim($buffer, "\n"));
});
if(!$process->isSuccessful())
{
unlink($hex_dump_file);
throw new BuildException(sprintf("Unable to compile the binary, gcc exited with code %d: %s", $process->getExitCode(), $process->getErrorOutput()));
}
// Finally, remove the hex dump file and return the executable path
unlink($hex_dump_file);
return $binary_path;
}
/**
* Creates a hex dump of the binary data and writes it to the output file suitable for inclusion in a C source
* file, this is a similar utility to xxd.
*
* @param string $input_path
* @param string $output_path
* @param string $variable_name
* @return void
*/
private function hexDump(string $input_path, string $output_path, string $variable_name): void
{
$input = fopen($input_path, 'rb');
$output = fopen($output_path, 'wb');
fwrite($output, sprintf("unsigned char %s[] = {\n", Functions::toSnakeCase($variable_name)));
$byte_count = 0;
// Convert the binary data to hex and write it to the output file
while (!feof($input))
{
$byte = fread($input, 1);
if (strlen($byte) === 1)
{
fwrite($output, sprintf(" 0x%02x,", ord($byte)));
$byte_count++;
}
// Write 12 bytes per line or when reaching the end of the file
if ($byte_count === 12 || feof($input))
{
fwrite($output, "\n");
$byte_count = 0;
}
}
// Close the output file
fseek($output, -2, SEEK_END);
fwrite($output, "\n");
fwrite($output, "};\n");
// Finally, close the input and output files
fclose($input);
fclose($output);
}
}

View file

@ -23,7 +23,9 @@
namespace ncc\Classes\PhpExtension; namespace ncc\Classes\PhpExtension;
use Exception; use Exception;
use ncc\Classes\PackageWriter;
use ncc\Enums\ComponentDataType; use ncc\Enums\ComponentDataType;
use ncc\Enums\Flags\ComponentFlags;
use ncc\Exceptions\IOException; use ncc\Exceptions\IOException;
use ncc\Exceptions\PathNotFoundException; use ncc\Exceptions\PathNotFoundException;
use ncc\Objects\Package\Component; use ncc\Objects\Package\Component;
@ -32,34 +34,44 @@
use ncc\Utilities\Console; use ncc\Utilities\Console;
use ncc\Utilities\Functions; use ncc\Utilities\Functions;
use ncc\Utilities\IO; use ncc\Utilities\IO;
use ncc\ZiProto\ZiProto; use ncc\Extensions\ZiProto\ZiProto;
class NccCompiler extends \ncc\Classes\NccExtension\NccCompiler class NccCompiler extends \ncc\Classes\NccExtension\NccCompiler
{ {
/** /**
* @param PackageWriter $package_writer
* @param string $file_path * @param string $file_path
* @return Component * @return void
* @throws IOException * @throws IOException
* @throws PathNotFoundException * @throws PathNotFoundException
* @noinspection UnusedFunctionResultInspection
*/ */
public function buildComponent(string $file_path): Component public function processComponent(PackageWriter $package_writer, string $file_path): void
{ {
$parser = (new ParserFactory())->create(ParserFactory::PREFER_PHP7); $component_name = Functions::removeBasename($file_path);
try try
{ {
$encoded = json_encode($parser->parse(IO::fread($file_path)), JSON_THROW_ON_ERROR); $stmts = (new ParserFactory())->create(ParserFactory::PREFER_PHP7)->parse(IO::fread($file_path));
return new Component(Functions::removeBasename($file_path), ZiProto::encode(json_decode($encoded, true, 512, JSON_THROW_ON_ERROR)), ComponentDataType::AST);
$component = new Component($component_name, ZiProto::encode($stmts), ComponentDataType::AST);
$component->addFlag(ComponentFlags::PHP_AST);
$pointer = $package_writer->addComponent($component);
foreach(AstWalker::extractClasses($stmts) as $class)
{
$package_writer->mapClass($class, (int)$pointer[0], (int)$pointer[1]);
}
return;
} }
catch(Exception $e) catch(Exception $e)
{ {
Console::outWarning(sprintf('Failed to compile file "%s" with error "%s"', $file_path, $e->getMessage())); Console::outWarning(sprintf('Failed to compile file "%s" with error "%s"', $file_path, $e->getMessage()));
} }
return new Component( $component = new Component($component_name, Base64::encode(IO::fread($file_path)), ComponentDataType::BASE64_ENCODED);
Functions::removeBasename($file_path), $component->addFlag(ComponentFlags::PHP_B64);
Base64::encode(IO::fread($file_path)), ComponentDataType::BASE64_ENCODED $package_writer->addComponent($component);
);
} }
} }

View file

@ -1,356 +0,0 @@
<?php
/*
* Copyright (c) Nosial 2022-2023, all rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, including without
* limitation the rights 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:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
/** @noinspection PhpPropertyOnlyWrittenInspection */
/** @noinspection PhpMissingFieldTypeInspection */
namespace ncc\Classes\PhpExtension;
use ArrayIterator;
use Exception;
use ncc\Enums\ComponentDataType;
use ncc\Enums\ComponentFileExtensions;
use ncc\Exceptions\IntegrityException;
use ncc\Exceptions\IOException;
use ncc\Exceptions\NotSupportedException;
use ncc\Exceptions\PathNotFoundException;
use ncc\Interfaces\InstallerInterface;
use ncc\Objects\InstallationPaths;
use ncc\Objects\Package;
use ncc\Objects\Package\Component;
use ncc\Objects\Package\Resource;
use ncc\ThirdParty\nikic\PhpParser\Comment;
use ncc\ThirdParty\nikic\PhpParser\Node;
use ncc\ThirdParty\nikic\PhpParser\PrettyPrinter\Standard;
use ncc\ThirdParty\theseer\Autoload\CollectorException;
use ncc\ThirdParty\theseer\Autoload\CollectorResult;
use ncc\ThirdParty\theseer\Autoload\Config;
use ncc\ThirdParty\theseer\Autoload\Factory;
use ncc\Utilities\Base64;
use ncc\Utilities\IO;
use ReflectionClass;
use ReflectionException;
use RuntimeException;
use SplFileInfo;
use function is_array;
use function is_string;
class PhpInstaller implements InstallerInterface
{
/**
* @var ReflectionClass[] Node type to reflection class map
*/
private $reflection_class;
/**
* @inheritDoc
*/
public function __construct(Package $package)
{
}
/**
* Processes the given component and returns the decoded component as a string representation
* If the processed component does not result in a string representation, none will be returned.
*
* @param Component $component
* @return string|null
* @throws IntegrityException
* @throws NotSupportedException
*/
public function processComponent(Package\Component $component): ?string
{
if($component->getData() === null)
{
return null;
}
if(!$component->validateChecksum())
{
throw new IntegrityException(sprintf('Checksum validation failed for component: %s', $component->getName()));
}
switch($component->getDataType())
{
case ComponentDataType::AST:
try
{
$stmts = $this->decodeRecursive($component->getData());
}
catch (Exception $e)
{
throw new IntegrityException(sprintf('Cannot decode component: %s, %s', $component->getName(), $e->getMessage()));
}
return (new Standard())->prettyPrintFile($stmts);
case ComponentDataType::BASE64_ENCODED:
return Base64::decode($component->getData());
case ComponentDataType::PLAIN:
return $component->getData();
default:
throw new NotSupportedException(sprintf('Component data type %s is not supported.', $component->getDataType()));
}
}
/**
* @inheritDoc
*/
public function preInstall(InstallationPaths $installationPaths): void
{
}
/**
* @inheritDoc
*/
public function postInstall(InstallationPaths $installationPaths): void
{
$autoload_path = $installationPaths->getBinPath() . DIRECTORY_SEPARATOR . 'autoload.php';
$autoload_src = $this->generateAutoload($installationPaths->getSourcePath(), $autoload_path);
IO::fwrite($autoload_path, $autoload_src);
}
/**
* Processes the given resource and returns the string representation of the resource
*
* @param Resource $resource
* @return string|null
* @throws IntegrityException
*/
public function processResource(Package\Resource $resource): ?string
{
if(!$resource->validateChecksum())
{
throw new IntegrityException('Checksum validation failed for resource ' . $resource->getName() . ', the package may be corrupted.');
}
return Base64::decode($resource->getData());
}
/**
* @param $value
* @return array|Comment|Node
* @throws ReflectionException
* @noinspection PhpMissingReturnTypeInspection
*/
private function decodeRecursive($value)
{
if (is_array($value))
{
if (isset($value['nodeType']))
{
if ($value['nodeType'] === 'Comment' || $value['nodeType'] === 'Comment_Doc')
{
return $this->decodeComment($value);
}
return $this->decodeNode($value);
}
return $this->decodeArray($value);
}
return $value;
}
/**
* @param array $array
* @return array
* @throws ReflectionException
*/
private function decodeArray(array $array) : array
{
$decodedArray = [];
foreach ($array as $key => $value)
{
$decodedArray[$key] = $this->decodeRecursive($value);
}
return $decodedArray;
}
/**
* @param array $value
* @return Node
* @throws ReflectionException
*/
private function decodeNode(array $value) : Node
{
$nodeType = $value['nodeType'];
if (!is_string($nodeType))
{
throw new RuntimeException('Node type must be a string');
}
$reflectionClass = $this->reflectionClassFromNodeType($nodeType);
/** @var Node $node */
$node = $reflectionClass->newInstanceWithoutConstructor();
if (isset($value['attributes'])) {
if (!is_array($value['attributes']))
{
throw new RuntimeException('Attributes must be an array');
}
$node->setAttributes($this->decodeArray($value['attributes']));
}
foreach ($value as $name => $subNode) {
if ($name === 'nodeType' || $name === 'attributes')
{
continue;
}
$node->$name = $this->decodeRecursive($subNode);
}
return $node;
}
/**
* @param array $value
* @return Comment
*/
private function decodeComment(array $value) : Comment
{
$className = $value['nodeType'] === 'Comment' ? Comment::class : Comment\Doc::class;
if (!isset($value['text']))
{
throw new RuntimeException('Comment must have text');
}
return new $className(
$value['text'],
$value['line'] ?? -1, $value['filePos'] ?? -1, $value['tokenPos'] ?? -1,
$value['endLine'] ?? -1, $value['endFilePos'] ?? -1, $value['endTokenPos'] ?? -1
);
}
/**
* @param string $nodeType
* @return ReflectionClass
* @throws ReflectionException
*/
private function reflectionClassFromNodeType(string $nodeType) : ReflectionClass
{
if (!isset($this->reflection_class[$nodeType]))
{
$className = $this->classNameFromNodeType($nodeType);
$this->reflection_class[$nodeType] = new ReflectionClass($className);
}
return $this->reflection_class[$nodeType];
}
/**
* @param string $nodeType
* @return string
*/
private function classNameFromNodeType(string $nodeType) : string
{
$className = 'ncc\\ThirdParty\\nikic\\PhpParser\\Node\\' . str_replace('_', '\\', $nodeType);
if (class_exists($className))
{
return $className;
}
$className .= '_';
if (class_exists($className))
{
return $className;
}
throw new RuntimeException("Unknown node type \"$nodeType\"");
}
/**
* Processes the project and generates the autoloader source code.
*
* @param string $src
* @param string $output
* @return string
* @throws CollectorException
* @throws IOException
* @throws PathNotFoundException
*/
private function generateAutoload(string $src, string $output): string
{
// Construct configuration
$configuration = new Config([$src]);
$configuration->setFollowSymlinks(false); // Don't follow symlinks, it won't work on some systems.
$configuration->setTrusting(true); // Paranoid
$configuration->setOutputFile($output);
$configuration->setStaticMode(false);
// Official PHP file extensions that are missing from the default configuration (whatever)
$configuration->setInclude(ComponentFileExtensions::PHP);
$configuration->setQuietMode(true);
$configuration->setTolerantMode(true);
// Construct factory
$factory = new Factory();
$factory->setConfig($configuration);
// Create Collector
$result = self::runCollector($factory, $configuration);
// Exception raises when there are no files in the project that can be processed by the autoloader
$template = IO::fread($configuration->getTemplate());
return $factory->getRenderer($result)->render($template);
}
/**
* Iterates through the target directories through the collector and returns the collector results.
*
* @param Factory $factory
* @param Config $config
* @return CollectorResult
* @throws CollectorException
* @throws Exception
*/
private static function runCollector(Factory $factory, Config $config): CollectorResult
{
$collector = $factory->getCollector();
foreach($config->getDirectories() as $directory)
{
if(is_dir($directory))
{
$scanner = $factory->getScanner()->getIterator($directory);
$collector->processDirectory($scanner);
unset($scanner);
}
else
{
$file = new SplFileInfo($directory);
$filter = $factory->getFilter(new ArrayIterator(array($file)));
foreach($filter as $file)
{
$collector->processFile($file);
}
}
}
return $collector->getResult();
}
}

View file

@ -1,120 +0,0 @@
<?php
/*
* Copyright (c) Nosial 2022-2023, all rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, including without
* limitation the rights 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:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
namespace ncc\Classes\PhpExtension;
use Exception;
use ncc\Enums\Options\RuntimeImportOptions;
use ncc\Classes\NccExtension\ConstantCompiler;
use ncc\Exceptions\ImportException;
use ncc\Exceptions\IntegrityException;
use ncc\Interfaces\RuntimeInterface;
use ncc\Objects\PackageLock\VersionEntry;
use ncc\Objects\ProjectConfiguration\Assembly;
use ncc\Runtime\Constants;
use ncc\Utilities\IO;
use ncc\ZiProto\ZiProto;
class PhpRuntime implements RuntimeInterface
{
/**
* Attempts to import a PHP package
*
* @param VersionEntry $versionEntry
* @param array $options
* @return bool
* @throws ImportException
*/
public static function import(VersionEntry $versionEntry, array $options=[]): bool
{
$autoload_path = $versionEntry->getInstallPaths()->getBinPath() . DIRECTORY_SEPARATOR . 'autoload.php';
$static_files = $versionEntry->getInstallPaths()->getBinPath() . DIRECTORY_SEPARATOR . 'static_autoload.bin';
$constants_path = $versionEntry->getInstallPaths()->getDataPath() . DIRECTORY_SEPARATOR . 'const';
$assembly_path = $versionEntry->getInstallPaths()->getDataPath() . DIRECTORY_SEPARATOR . 'assembly';
if(!file_exists($assembly_path))
{
throw new ImportException('Cannot locate assembly file \'' . $assembly_path . '\'');
}
try
{
$assembly_content = ZiProto::decode(IO::fread($assembly_path));
$assembly = Assembly::fromArray($assembly_content);
}
catch(Exception $e)
{
throw new ImportException('Failed to load assembly file \'' . $assembly_path . '\': ' . $e->getMessage());
}
if(file_exists($constants_path))
{
try
{
$constants = ZiProto::decode(IO::fread($constants_path));
}
catch(Exception $e)
{
throw new ImportException('Failed to load constants file \'' . $constants_path . '\': ' . $e->getMessage());
}
foreach($constants as $name => $value)
{
$value = ConstantCompiler::compileRuntimeConstants($value);
try
{
Constants::register($assembly->getPackage(), $name, $value, true);
}
catch (IntegrityException $e)
{
trigger_error('Cannot set constant \'' . $name . '\', ' . $e->getMessage(), E_USER_WARNING);
}
}
}
if(file_exists($autoload_path) && !in_array(RuntimeImportOptions::IMPORT_AUTOLOADER, $options, true))
{
require_once($autoload_path);
}
if(file_exists($static_files) && !in_array(RuntimeImportOptions::IMPORT_STATIC_FILES, $options, true))
{
try
{
$static_files = ZiProto::decode(IO::fread($static_files));
foreach($static_files as $file)
{
require_once($file);
}
}
catch(Exception $e)
{
throw new ImportException('Failed to load static files: ' . $e->getMessage(), $e);
}
}
return !(!file_exists($autoload_path) && !file_exists($static_files));
}
}

View file

@ -1,17 +0,0 @@
<?php
if (PHP_SAPI !== 'cli')
{
print('%ASSEMBLY.PACKAGE% must be run from the command line.' . PHP_EOL);
exit(1);
}
if(!isset($argv))
{
trigger_error('No $argv found, maybe you are using php-cgi?', E_USER_ERROR);
}
require('ncc');
import('%ASSEMBLY.PACKAGE%', 'latest');
\%ASSEMBLY.NAME%\Program::main($argv);

View file

@ -20,7 +20,7 @@
* *
*/ */
namespace ncc\Classes\PhpExtension; namespace ncc\Classes\PhpExtension\Templates;
use ncc\Classes\NccExtension\ConstantCompiler; use ncc\Classes\NccExtension\ConstantCompiler;
use ncc\Enums\Options\ProjectOptions; use ncc\Enums\Options\ProjectOptions;
@ -33,7 +33,7 @@
use ncc\Objects\ProjectConfiguration\ExecutionPolicy; use ncc\Objects\ProjectConfiguration\ExecutionPolicy;
use ncc\Utilities\IO; use ncc\Utilities\IO;
class PhpCliTemplate implements TemplateInterface class CliTemplate implements TemplateInterface
{ {
/** /**
* @inheritDoc * @inheritDoc
@ -71,7 +71,7 @@
IO::fwrite( IO::fwrite(
$project_manager->getProjectSourcePath() . DIRECTORY_SEPARATOR . 'Program.php', $project_manager->getProjectSourcePath() . DIRECTORY_SEPARATOR . 'Program.php',
ConstantCompiler::compileConstants($project_manager->getProjectConfiguration(), ConstantCompiler::compileConstants($project_manager->getProjectConfiguration(),
IO::fread(__DIR__ . DIRECTORY_SEPARATOR . 'TemplateFiles' . DIRECTORY_SEPARATOR . 'Program.php.tpl') IO::fread(__DIR__ . DIRECTORY_SEPARATOR . 'Program.php.tpl')
) )
); );
} }
@ -89,7 +89,7 @@
IO::fwrite( IO::fwrite(
$project_manager->getProjectPath() . DIRECTORY_SEPARATOR . 'main', $project_manager->getProjectPath() . DIRECTORY_SEPARATOR . 'main',
ConstantCompiler::compileConstants($project_manager->getProjectConfiguration(), ConstantCompiler::compileConstants($project_manager->getProjectConfiguration(),
IO::fread(__DIR__ . DIRECTORY_SEPARATOR . 'TemplateFiles' . DIRECTORY_SEPARATOR . 'main.php.tpl') IO::fread(__DIR__ . DIRECTORY_SEPARATOR . 'main.php.tpl')
) )
); );
} }
@ -107,7 +107,7 @@
IO::fwrite( IO::fwrite(
$project_manager->getProjectPath() . DIRECTORY_SEPARATOR . 'Makefile', $project_manager->getProjectPath() . DIRECTORY_SEPARATOR . 'Makefile',
ConstantCompiler::compileConstants($project_manager->getProjectConfiguration(), ConstantCompiler::compileConstants($project_manager->getProjectConfiguration(),
IO::fread(__DIR__ . DIRECTORY_SEPARATOR . 'TemplateFiles' . DIRECTORY_SEPARATOR . 'Makefile.tpl') IO::fread(__DIR__ . DIRECTORY_SEPARATOR . 'Makefile.tpl')
) )
); );
} }

View file

@ -20,7 +20,7 @@
* *
*/ */
namespace ncc\Classes\PhpExtension; namespace ncc\Classes\PhpExtension\Templates;
use ncc\Classes\NccExtension\ConstantCompiler; use ncc\Classes\NccExtension\ConstantCompiler;
use ncc\Exceptions\IOException; use ncc\Exceptions\IOException;
@ -29,7 +29,7 @@
use ncc\Managers\ProjectManager; use ncc\Managers\ProjectManager;
use ncc\Utilities\IO; use ncc\Utilities\IO;
class PhpLibraryTemplate implements TemplateInterface class LibraryTemplate implements TemplateInterface
{ {
/** /**
* @inheritDoc * @inheritDoc

View file

@ -7,11 +7,12 @@
/** /**
* %ASSEMBLY.NAME% main entry point * %ASSEMBLY.NAME% main entry point
* *
* @param string[] $args * @param string[] $args Command-line arguments
* @return void * @return int Exit code
*/ */
public static function main(array $args): void public static function main(array $args): int
{ {
print("Hello World from %ASSEMBLY.PACKAGE%!" . PHP_EOL); print("Hello World from %ASSEMBLY.PACKAGE%!" . PHP_EOL);
return 0;
} }
} }

View file

@ -0,0 +1,24 @@
<?php
if (PHP_SAPI !== 'cli')
{
print('%ASSEMBLY.PACKAGE% must be run from the command line.' . PHP_EOL);
exit(1);
}
if(!isset($argv))
{
if(isset($_SERVER['argv']))
{
$argv = $_SERVER['argv'];
}
else
{
print('%ASSEMBLY.PACKAGE% failed to run, no $argv found.' . PHP_EOL);
exit(1);
}
}
require('ncc');
\ncc\Classes\Runtime::import('%ASSEMBLY.PACKAGE%', 'latest');
exit(\%ASSEMBLY.NAME%\Program::main($argv));

View file

@ -0,0 +1,53 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>
int main(int argc, char *argv[])
{
// Get the program's file path
char programPath[PATH_MAX];
ssize_t pathLength = readlink("/proc/self/exe", programPath, sizeof(programPath) - 1);
if (pathLength == -1)
{
perror("readlink");
return 1;
}
programPath[pathLength] = '\0';
// Calculate the total length needed for the command string
size_t totalLength = snprintf(NULL, 0, "ncc exec --package=\"%s\" --exec-args", programPath);
for (int i = 1; i < argc; i++)
{
totalLength += snprintf(NULL, 0, " \"%s\"", argv[i]) + 1; // +1 for space or null terminator
}
// Allocate memory for the command string
char *command = (char *)malloc(totalLength + 1); // +1 for null terminator
if (command == NULL)
{
perror("malloc");
return 1;
}
// Construct the command to execute
snprintf(command, totalLength + 1, "ncc exec --package=\"%s\" --exec-args", programPath);
for (int i = 1; i < argc; i++)
{
snprintf(command + strlen(command), totalLength - strlen(command) + 1, " \"%s\"", argv[i]);
}
// Execute the ncc command
int result = system(command);
free(command);
if (result == -1)
{
perror("system");
return 1;
}
return WEXITSTATUS(result);
}

View file

@ -22,44 +22,47 @@
namespace ncc\Classes\PythonExtension; namespace ncc\Classes\PythonExtension;
use Exception;
use ncc\Classes\ExecutionUnitRunner;
use ncc\Exceptions\IOException; use ncc\Exceptions\IOException;
use ncc\Exceptions\PathNotFoundException; use ncc\Exceptions\OperationException;
use ncc\Interfaces\RunnerInterface; use ncc\Interfaces\RunnerInterface;
use ncc\Objects\Package\ExecutionUnit; use ncc\Objects\Package\ExecutionUnit;
use ncc\Objects\ProjectConfiguration\ExecutionPolicy;
use ncc\Utilities\IO; use ncc\Utilities\IO;
use ncc\Utilities\PathFinder;
class PythonRunner implements RunnerInterface class PythonRunner implements RunnerInterface
{ {
/** /**
* @inheritDoc * @inheritDoc
* @param string $path
* @param ExecutionPolicy $policy
* @return ExecutionUnit
* @throws IOException * @throws IOException
* @throws PathNotFoundException * @throws OperationException
*/ */
public static function processUnit(string $path, ExecutionPolicy $policy): ExecutionUnit public static function executeUnit(ExecutionUnit $unit, array $args=[], bool $local=true): int
{ {
$execution_unit = new ExecutionUnit(); $tmp = PathFinder::getCachePath() . DIRECTORY_SEPARATOR . hash('sha1', $unit->getData()) . '.py';
IO::fwrite($tmp, $unit->getData(), 0777);
if(!file_exists($path) && !is_file($path)) try
{ {
throw new PathNotFoundException($path); $process = ExecutionUnitRunner::constructProcess($unit, array_merge([$tmp], $args));
$process->run(static function($type, $buffer) use ($unit)
{
if(!$unit->getExecutionPolicy()->getExecute()->isSilent())
{
print($buffer);
}
});
}
catch(Exception $e)
{
throw new OperationException(sprintf('There was an error executing the python execution unit %s: %s', $unit->getExecutionPolicy()->getName(), $e->getMessage()), $e);
}
finally
{
unlink($tmp);
} }
$execution_unit->setExecutionPolicy($policy); return $process->getExitCode();
$execution_unit->setData(IO::fread($path));
return $execution_unit;
}
/**
* @inheritDoc
*/
public static function getFileExtension(): string
{
return '.py';
} }
} }

257
src/ncc/Classes/Runtime.php Normal file
View file

@ -0,0 +1,257 @@
<?php
/*
* Copyright (c) Nosial 2022-2023, all rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, including without
* limitation the rights 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:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
/** @noinspection PhpMissingFieldTypeInspection */
namespace ncc\Classes;
use Exception;
use InvalidArgumentException;
use ncc\Enums\FileDescriptor;
use ncc\Enums\Runners;
use ncc\Enums\Versions;
use ncc\Exceptions\ConfigurationException;
use ncc\Exceptions\ImportException;
use ncc\Exceptions\IOException;
use ncc\Exceptions\NotSupportedException;
use ncc\Exceptions\PathNotFoundException;
use ncc\Extensions\ZiProto\ZiProto;
use ncc\Managers\PackageManager;
use ncc\Objects\Package\Metadata;
use ncc\Utilities\IO;
use RuntimeException;
class Runtime
{
/**
* @var array
*/
private static $imported_packages = [];
/**
* @var array
*/
private static $class_map = [];
/**
* @var PackageManager|null
*/
private static $package_manager;
/**
* Executes the main execution point of an imported package and returns the evaluated result
* This method may exit the program without returning a value
*
* @param string $package
* @return mixed
* @throws ConfigurationException
* @throws IOException
* @throws PathNotFoundException
* @throws NotSupportedException
*/
public static function execute(string $package): int
{
if(!self::isImported($package))
{
throw new InvalidArgumentException(sprintf('Package %s is not imported', $package));
}
if(self::$imported_packages[$package] instanceof PackageReader)
{
return ExecutionUnitRunner::executeFromPackage(
self::$imported_packages[$package],
self::$imported_packages[$package]->getMetadata()->getMainExecutionPolicy()
);
}
if(is_string(self::$imported_packages[$package]))
{
$metadata_path = self::$imported_packages[$package] . DIRECTORY_SEPARATOR . FileDescriptor::METADATA;
if(!is_file($metadata_path))
{
throw new RuntimeException(sprintf('The package %s does not have a metadata file (is it corrupted?)', $package));
}
return ExecutionUnitRunner::executeFromSystem(
self::$imported_packages[$package],
Metadata::fromArray(ZiProto::decode(IO::fread($metadata_path)))->getMainExecutionPolicy()
);
}
throw new RuntimeException('Unable to execute the main execution point of the package, this is probably a bug');
}
/**
* @param string $package
* @param string $version
* @return string
* @throws ConfigurationException
* @throws IOException
* @throws ImportException
* @throws PathNotFoundException
*/
public static function import(string $package, string $version=Versions::LATEST): string
{
if(self::isImported($package))
{
return $package;
}
if(is_file($package))
{
return self::importFromPackage(realpath($package));
}
if(self::getPackageManager()->getPackageLock()->entryExists($package))
{
return self::importFromSystem($package, $version);
}
throw new RuntimeException('Importing from a package name is not supported yet');
}
/**
* @param string $package
* @param string $version
* @return string
* @throws IOException
* @throws PathNotFoundException
*/
private static function importFromSystem(string $package, string $version=Versions::LATEST): string
{
$entry = self::getPackageManager()->getPackageLock()->getEntry($package);
foreach($entry->getClassMap($version) as $class => $component_name)
{
$component_path = $entry->getPath($version) . DIRECTORY_SEPARATOR . 'bin' . DIRECTORY_SEPARATOR . $component_name;
self::$class_map[strtolower($class)] = $component_path;
}
self::$imported_packages[$package] = $entry->getPath($version);
return $package;
}
/**
* Imports a package from a package file
*
* @param string $package_path
* @return string
* @throws ConfigurationException
* @throws ImportException
*/
private static function importFromPackage(string $package_path): string
{
try
{
$package_reader = new PackageReader($package_path);
}
catch(Exception $e)
{
throw new RuntimeException(sprintf('Failed to import package from file "%s" due to an exception: %s', $package_path, $e->getMessage()), 0, $e);
}
// Check if the package is already imported
if(in_array($package_reader->getAssembly()->getPackage(), self::$imported_packages, true))
{
$package_name = $package_reader->getAssembly()->getPackage();
unset($package_reader);
return $package_name;
}
// Import the package
$package_name = $package_reader->getAssembly()->getPackage();
self::$imported_packages[$package_name] = $package_reader;
// Register the autoloader
foreach($package_reader->getClassMap() as $value)
{
self::$class_map[strtolower($value)] = static function() use ($value, $package_name)
{
return self::$imported_packages[$package_name]->getComponentByClass($value)->getData();
};
}
return $package_reader->getAssembly()->getPackage();
}
/**
* Determines if the package is already imported
*
* @param string $package
* @return bool
*/
public static function isImported(string $package): bool
{
return isset(self::$imported_packages[$package]);
}
/**
* Returns an array of all the packages that is currently imported
*
* @return array
*/
public static function getImportedPackages(): array
{
return array_keys(self::$imported_packages);
}
/**
* @param string $class
* @return void
*/
public static function autoloadHandler(string $class): void
{
$class = strtolower($class);
if(!isset(self::$class_map[$class]))
{
return;
}
if(is_callable(self::$class_map[$class]))
{
eval(self::$class_map[$class]());
return;
}
if(is_string(self::$class_map[$class]) && is_file(self::$class_map[$class]))
{
require_once self::$class_map[$class];
return;
}
}
/**
* @return PackageManager
*/
private static function getPackageManager(): PackageManager
{
if(self::$package_manager === null)
{
self::$package_manager = new PackageManager();
}
return self::$package_manager;
}
}

View file

@ -25,4 +25,5 @@
final class BuildOutputType final class BuildOutputType
{ {
public const NCC_PACKAGE = 'ncc'; public const NCC_PACKAGE = 'ncc';
public const EXECUTABLE = 'executable';
} }

View file

@ -34,11 +34,6 @@
*/ */
public const PLAIN = 'plain'; public const PLAIN = 'plain';
/**
* Indicates whether the component is represented as bytecode
*/
public const BYTECODE = 'bytecode';
/** /**
* Indicates whether the component is represented as binary or executable * Indicates whether the component is represented as binary or executable
*/ */

View file

@ -0,0 +1,34 @@
<?php
/*
* Copyright (c) Nosial 2022-2023, all rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, including without
* limitation the rights 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:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
namespace ncc\Enums;
final class FileDescriptor
{
public const ASSEMBLY = 'ASSEMBLY';
public const METADATA = 'METADATA';
public const INSTALLER = 'INSTALLER';
public const CLASS_MAP = 'CLASS_MAP';
}

View file

@ -20,46 +20,17 @@
* *
*/ */
namespace ncc\Classes\PythonExtension; namespace ncc\Enums\Flags;
use ncc\Exceptions\IOException; final class ComponentFlags
use ncc\Exceptions\PathNotFoundException;
use ncc\Interfaces\RunnerInterface;
use ncc\Objects\Package\ExecutionUnit;
use ncc\Objects\ProjectConfiguration\ExecutionPolicy;
use ncc\Utilities\IO;
class Python2Runner implements RunnerInterface
{ {
/**
* Indicates that the component is the AST of a PHP file encoded with msgpack.
*/
public const PHP_AST = 'php_ast';
/** /**
* @inheritDoc * Indicates that the component is a PHP file encoded with base64.
* @param string $path
* @param ExecutionPolicy $policy
* @return ExecutionUnit
* @throws IOException
* @throws PathNotFoundException
*/ */
public static function processUnit(string $path, ExecutionPolicy $policy): ExecutionUnit public const PHP_B64 = 'php_b64';
{
$execution_unit = new ExecutionUnit();
if(!file_exists($path) && !is_file($path))
{
throw new PathNotFoundException($path);
}
$execution_unit->setExecutionPolicy($policy);
$execution_unit->setData(IO::fread($path));
return $execution_unit;
}
/**
* @inheritDoc
*/
public static function getFileExtension(): string
{
return '.py';
}
} }

View file

@ -0,0 +1,34 @@
<?php
/*
* Copyright (c) Nosial 2022-2023, all rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, including without
* limitation the rights 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:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
namespace ncc\Enums\Flags;
final class PackageFlags
{
public const COMPRESSION = 'gzip';
public const LOW_COMPRESSION = 'low_gz`';
public const MEDIUM_COMPRESSION = 'medium_gz';
public const HIGH_COMPRESSION = 'high_gz';
}

View file

@ -0,0 +1,28 @@
<?php
/*
* Copyright (c) Nosial 2022-2023, all rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, including without
* limitation the rights 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:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
namespace ncc\Enums\Options;
final class BuildConfigurationOptions
{
public const COMPRESSION = 'compression';
}

View file

@ -0,0 +1,32 @@
<?php
/*
* Copyright (c) Nosial 2022-2023, all rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, including without
* limitation the rights 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:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
namespace ncc\Enums\Options\BuildConfigurationOptions;
final class CompressionOptions
{
public const HIGH = 'high';
public const MEDIUM = 'medium';
public const LOW = 'low';
}

View file

@ -0,0 +1,28 @@
<?php
/*
* Copyright (c) Nosial 2022-2023, all rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, including without
* limitation the rights 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:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
namespace ncc\Enums\Options;
final class ComponentDecodeOptions
{
public const AS_FILE = 'as_file';
}

View file

@ -20,46 +20,23 @@
* *
*/ */
namespace ncc\Classes\PythonExtension; namespace ncc\Enums;
use ncc\Exceptions\IOException; final class PackageDirectory
use ncc\Exceptions\PathNotFoundException;
use ncc\Interfaces\RunnerInterface;
use ncc\Objects\Package\ExecutionUnit;
use ncc\Objects\ProjectConfiguration\ExecutionPolicy;
use ncc\Utilities\IO;
class Python3Runner implements RunnerInterface
{ {
public const ASSEMBLY = 0x61737365;
/** public const METADATA = 0x6D657461;
* @inheritDoc
* @param string $path
* @param ExecutionPolicy $policy
* @return ExecutionUnit
* @throws IOException
* @throws PathNotFoundException
*/
public static function processUnit(string $path, ExecutionPolicy $policy): ExecutionUnit
{
$execution_unit = new ExecutionUnit();
if(!file_exists($path) && !is_file($path)) public const INSTALLER = 0x696E7374;
{
throw new PathNotFoundException($path);
}
$execution_unit->setExecutionPolicy($policy); public const DEPENDENCIES = 0x64657065;
$execution_unit->setData(IO::fread($path));
return $execution_unit; public const EXECUTION_UNITS = 0x65786563;
}
/** public const COMPONENTS = 0x636F6D70;
* @inheritDoc
*/ public const RESOURCES = 0x7265736F;
public static function getFileExtension(): string
{ public const CLASS_POINTER = 0x636C6173;
return '.py';
}
} }

View file

@ -30,10 +30,6 @@ namespace ncc\Enums;
public const PYTHON = 'python'; public const PYTHON = 'python';
public const PYTHON_3 = 'python3';
public const PYTHON_2 = 'python2';
public const PERL = 'perl'; public const PERL = 'perl';
public const LUA = 'lua'; public const LUA = 'lua';

View file

@ -1,24 +1,24 @@
<?php <?php
/* /*
* Copyright (c) Nosial 2022-2023, all rights reserved. * Copyright (c) Nosial 2022-2023, all rights reserved.
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, including without * associated documentation files (the "Software"), to deal in the Software without restriction, including without
* limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the * limitation the rights 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 * Software, and to permit persons to whom the Software is furnished to do so, subject to the following
* conditions: * conditions:
* *
* The above copyright notice and this permission notice shall be included in all copies or substantial portions * The above copyright notice and this permission notice shall be included in all copies or substantial portions
* of the Software. * of the Software.
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE. * DEALINGS IN THE SOFTWARE.
* *
*/ */
namespace ncc\Enums; namespace ncc\Enums;
@ -32,12 +32,12 @@
/** /**
* The current version of the package structure file format * The current version of the package structure file format
*/ */
public const PACKAGE_STRUCTURE_VERSION = '1.0'; public const PACKAGE_STRUCTURE_VERSION = '2.0';
/** /**
* The current version of the package lock structure file format * The current version of the package lock structure file format
*/ */
public const PACKAGE_LOCK_VERSION = '1.0.0'; public const PACKAGE_LOCK_VERSION = '2.0.0';
/** /**
* Generic version of the package structure file format (latest) * Generic version of the package structure file format (latest)

View file

@ -1,42 +1,42 @@
<?php <?php
/* /*
* Copyright (c) Nosial 2022-2023, all rights reserved. * Copyright (c) Nosial 2022-2023, all rights reserved.
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, including without * associated documentation files (the "Software"), to deal in the Software without restriction, including without
* limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the * limitation the rights 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 * Software, and to permit persons to whom the Software is furnished to do so, subject to the following
* conditions: * conditions:
* *
* The above copyright notice and this permission notice shall be included in all copies or substantial portions * The above copyright notice and this permission notice shall be included in all copies or substantial portions
* of the Software. * of the Software.
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE. * DEALINGS IN THE SOFTWARE.
* *
*/ */
namespace ncc\ZiProto\Abstracts; namespace ncc\Extensions\ZiProto\Abstracts;
/** /**
* Class Options * Class Options
* @package ncc\ZiProto\Abstracts * @package ncc\ZiProto\Abstracts
*/ */
abstract class Options final class Options
{ {
const BIGINT_AS_STR = 0b001; public const BIGINT_AS_STR = 0b001;
const BIGINT_AS_GMP = 0b010; public const BIGINT_AS_GMP = 0b010;
const BIGINT_AS_EXCEPTION = 0b100; public const BIGINT_AS_EXCEPTION = 0b100;
const FORCE_STR = 0b00000001; public const FORCE_STR = 0b00000001;
const FORCE_BIN = 0b00000010; public const FORCE_BIN = 0b00000010;
const DETECT_STR_BIN = 0b00000100; public const DETECT_STR_BIN = 0b00000100;
const FORCE_ARR = 0b00001000; public const FORCE_ARR = 0b00001000;
const FORCE_MAP = 0b00010000; public const FORCE_MAP = 0b00010000;
const DETECT_ARR_MAP = 0b00100000; public const DETECT_ARR_MAP = 0b00100000;
const FORCE_FLOAT32 = 0b01000000; public const FORCE_FLOAT32 = 0b01000000;
const FORCE_FLOAT64 = 0b10000000; public const FORCE_FLOAT64 = 0b10000000;
} }

View file

@ -1,34 +1,34 @@
<?php <?php
/* /*
* Copyright (c) Nosial 2022-2023, all rights reserved. * Copyright (c) Nosial 2022-2023, all rights reserved.
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, including without * associated documentation files (the "Software"), to deal in the Software without restriction, including without
* limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the * limitation the rights 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 * Software, and to permit persons to whom the Software is furnished to do so, subject to the following
* conditions: * conditions:
* *
* The above copyright notice and this permission notice shall be included in all copies or substantial portions * The above copyright notice and this permission notice shall be included in all copies or substantial portions
* of the Software. * of the Software.
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE. * DEALINGS IN THE SOFTWARE.
* *
*/ */
namespace ncc\ZiProto\Abstracts; namespace ncc\Extensions\ZiProto\Abstracts;
/** /**
* Class Regex * Class Regex
* @package ncc\ZiProto\Abstracts * @package ncc\ZiProto\Abstracts
*/ */
abstract class Regex final class Regex
{ {
const UTF8_REGEX = '/\A(?: public const UTF8_REGEX = '/\A(?:
[\x00-\x7F]++ # ASCII [\x00-\x7F]++ # ASCII
| [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte | [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte
| \xE0[\xA0-\xBF][\x80-\xBF] # excluding over longs | \xE0[\xA0-\xBF][\x80-\xBF] # excluding over longs

View file

@ -1,37 +1,40 @@
<?php <?php
/*
* Copyright (c) Nosial 2022-2023, all rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, including without
* limitation the rights 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:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
namespace ncc\ZiProto; /** @noinspection PhpMissingFieldTypeInspection */
/*
* Copyright (c) Nosial 2022-2023, all rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, including without
* limitation the rights 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:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
namespace ncc\Extensions\ZiProto;
use function gmp_init; use function gmp_init;
use function ord; use function ord;
use function sprintf; use function sprintf;
use function substr; use function substr;
use function unpack; use function unpack;
use ncc\ZiProto\Exception\InsufficientDataException; use ncc\Extensions\ZiProto\Exception\InsufficientDataException;
use ncc\ZiProto\Exception\IntegerOverflowException; use ncc\Extensions\ZiProto\Exception\IntegerOverflowException;
use ncc\ZiProto\Exception\DecodingFailedException; use ncc\Extensions\ZiProto\Exception\DecodingFailedException;
use ncc\ZiProto\Exception\InvalidOptionException; use ncc\Extensions\ZiProto\Exception\InvalidOptionException;
use ncc\ncc\ZiProto\TypeTransformer\Extension; use ncc\Extensions\ZiProto\TypeTransformer\Extension;
/** /**
* Class BufferStream * Class BufferStream
@ -52,12 +55,12 @@ namespace ncc\ZiProto;
/** /**
* @var bool * @var bool
*/ */
private $isBigIntAsStr; private $big_int_as_str;
/** /**
* @var bool * @var bool
*/ */
private $isBigIntAsGmp; private $big_int_as_gmp;
/** /**
* @var Extension[]|null * @var Extension[]|null
@ -66,11 +69,10 @@ namespace ncc\ZiProto;
/** /**
* @param string $buffer * @param string $buffer
* @param DecodingOptions|int|null $options * @param int|DecodingOptions|null $options
*
* @throws InvalidOptionException * @throws InvalidOptionException
*/ */
public function __construct(string $buffer = '', $options = null) public function __construct(string $buffer = '', DecodingOptions|int|null $options=null)
{ {
if (null === $options) if (null === $options)
{ {
@ -85,8 +87,8 @@ namespace ncc\ZiProto;
$options = DecodingOptions::fromBitmask($options); $options = DecodingOptions::fromBitmask($options);
} }
$this->isBigIntAsStr = $options->isBigIntAsStrMode(); $this->big_int_as_str = $options->isBigIntAsStrMode();
$this->isBigIntAsGmp = $options->isBigIntAsGmpMode(); $this->big_int_as_gmp = $options->isBigIntAsGmpMode();
$this->buffer = $buffer; $this->buffer = $buffer;
} }
@ -94,7 +96,7 @@ namespace ncc\ZiProto;
* @param Extension $transformer * @param Extension $transformer
* @return BufferStream * @return BufferStream
*/ */
public function registerTransformer(Extension $transformer) : self public function registerTransformer(Extension $transformer): self
{ {
$this->transformers[$transformer->getType()] = $transformer; $this->transformers[$transformer->getType()] = $transformer;
return $this; return $this;
@ -114,7 +116,7 @@ namespace ncc\ZiProto;
* @param string $buffer * @param string $buffer
* @return BufferStream * @return BufferStream
*/ */
public function reset(string $buffer = '') : self public function reset(string $buffer='') : self
{ {
$this->buffer = $buffer; $this->buffer = $buffer;
$this->offset = 0; $this->offset = 0;
@ -203,64 +205,61 @@ namespace ncc\ZiProto;
return $c - 0x100; return $c - 0x100;
} }
switch ($c) return match ($c)
{ {
case 0xc0: return null; 0xc0 => null,
case 0xc2: return false; 0xc2 => false,
case 0xc3: return true; 0xc3 => true,
// bin // bin
case 0xd9: 0xd9, 0xc4 => $this->decodeStrData($this->decodeUint8()),
case 0xc4: return $this->decodeStrData($this->decodeUint8()); 0xda, 0xc5 => $this->decodeStrData($this->decodeUint16()),
case 0xda: 0xdb, 0xc6 => $this->decodeStrData($this->decodeUint32()),
case 0xc5: return $this->decodeStrData($this->decodeUint16());
case 0xdb:
case 0xc6: return $this->decodeStrData($this->decodeUint32());
// float // float
case 0xca: return $this->decodeFloat32(); 0xca => $this->decodeFloat32(),
case 0xcb: return $this->decodeFloat64(); 0xcb => $this->decodeFloat64(),
// uint // uint
case 0xcc: return $this->decodeUint8(); 0xcc => $this->decodeUint8(),
case 0xcd: return $this->decodeUint16(); 0xcd => $this->decodeUint16(),
case 0xce: return $this->decodeUint32(); 0xce => $this->decodeUint32(),
case 0xcf: return $this->decodeUint64(); 0xcf => $this->decodeUint64(),
// int // int
case 0xd0: return $this->decodeInt8(); 0xd0 => $this->decodeInt8(),
case 0xd1: return $this->decodeInt16(); 0xd1 => $this->decodeInt16(),
case 0xd2: return $this->decodeInt32(); 0xd2 => $this->decodeInt32(),
case 0xd3: return $this->decodeInt64(); 0xd3 => $this->decodeInt64(),
// str // str
// array // array
case 0xdc: return $this->decodeArrayData($this->decodeUint16()); 0xdc => $this->decodeArrayData($this->decodeUint16()),
case 0xdd: return $this->decodeArrayData($this->decodeUint32()); 0xdd => $this->decodeArrayData($this->decodeUint32()),
// map // map
case 0xde: return $this->decodeMapData($this->decodeUint16()); 0xde => $this->decodeMapData($this->decodeUint16()),
case 0xdf: return $this->decodeMapData($this->decodeUint32()); 0xdf => $this->decodeMapData($this->decodeUint32()),
// ext // ext
case 0xd4: return $this->decodeExtData(1); 0xd4 => $this->decodeExtData(1),
case 0xd5: return $this->decodeExtData(2); 0xd5 => $this->decodeExtData(2),
case 0xd6: return $this->decodeExtData(4); 0xd6 => $this->decodeExtData(4),
case 0xd7: return $this->decodeExtData(8); 0xd7 => $this->decodeExtData(8),
case 0xd8: return $this->decodeExtData(16); 0xd8 => $this->decodeExtData(16),
case 0xc7: return $this->decodeExtData($this->decodeUint8()); 0xc7 => $this->decodeExtData($this->decodeUint8()),
case 0xc8: return $this->decodeExtData($this->decodeUint16()); 0xc8 => $this->decodeExtData($this->decodeUint16()),
case 0xc9: return $this->decodeExtData($this->decodeUint32()); 0xc9 => $this->decodeExtData($this->decodeUint32()),
}
throw DecodingFailedException::unknownCode($c); default => throw DecodingFailedException::unknownCode($c), // Default case
};
} }
/** /**
* @return null * @return void
*/ */
public function decodeNil() public function decodeNil(): void
{ {
if (!isset($this->buffer[$this->offset])) if (!isset($this->buffer[$this->offset]))
{ {
@ -270,7 +269,7 @@ namespace ncc\ZiProto;
if ("\xc0" === $this->buffer[$this->offset]) if ("\xc0" === $this->buffer[$this->offset])
{ {
++$this->offset; ++$this->offset;
return null; return;
} }
throw DecodingFailedException::unexpectedCode(ord($this->buffer[$this->offset++]), 'nil'); throw DecodingFailedException::unexpectedCode(ord($this->buffer[$this->offset++]), 'nil');
@ -279,7 +278,7 @@ namespace ncc\ZiProto;
/** /**
* @return bool * @return bool
*/ */
public function decodeBool() public function decodeBool(): bool
{ {
if (!isset($this->buffer[$this->offset])) if (!isset($this->buffer[$this->offset]))
{ {
@ -348,7 +347,7 @@ namespace ncc\ZiProto;
/** /**
* @return mixed * @return mixed
*/ */
public function decodeFloat() public function decodeFloat(): mixed
{ {
if (!isset($this->buffer[$this->offset])) if (!isset($this->buffer[$this->offset]))
{ {
@ -374,7 +373,7 @@ namespace ncc\ZiProto;
/** /**
* @return string * @return string
*/ */
public function decodeStr() public function decodeStr(): string
{ {
if (!isset($this->buffer[$this->offset])) if (!isset($this->buffer[$this->offset]))
{ {
@ -410,7 +409,7 @@ namespace ncc\ZiProto;
/** /**
* @return string * @return string
*/ */
public function decodeBin() public function decodeBin(): string
{ {
if (!isset($this->buffer[$this->offset])) if (!isset($this->buffer[$this->offset]))
{ {
@ -441,7 +440,7 @@ namespace ncc\ZiProto;
/** /**
* @return array * @return array
*/ */
public function decodeArray() public function decodeArray(): array
{ {
$size = $this->decodeArrayHeader(); $size = $this->decodeArrayHeader();
$array = []; $array = [];
@ -457,7 +456,7 @@ namespace ncc\ZiProto;
/** /**
* @return int * @return int
*/ */
public function decodeArrayHeader() public function decodeArrayHeader(): int
{ {
if (!isset($this->buffer[$this->offset])) if (!isset($this->buffer[$this->offset]))
{ {
@ -488,7 +487,7 @@ namespace ncc\ZiProto;
/** /**
* @return array * @return array
*/ */
public function decodeMap() public function decodeMap(): array
{ {
$size = $this->decodeMapHeader(); $size = $this->decodeMapHeader();
$map = []; $map = [];
@ -504,7 +503,7 @@ namespace ncc\ZiProto;
/** /**
* @return int * @return int
*/ */
public function decodeMapHeader() public function decodeMapHeader(): int
{ {
if (!isset($this->buffer[$this->offset])) if (!isset($this->buffer[$this->offset]))
{ {
@ -535,7 +534,7 @@ namespace ncc\ZiProto;
/** /**
* @return mixed|Ext * @return mixed|Ext
*/ */
public function decodeExt() public function decodeExt(): mixed
{ {
if (!isset($this->buffer[$this->offset])) if (!isset($this->buffer[$this->offset]))
{ {
@ -563,7 +562,7 @@ namespace ncc\ZiProto;
/** /**
* @return int * @return int
*/ */
private function decodeUint8() private function decodeUint8(): int
{ {
if (!isset($this->buffer[$this->offset])) if (!isset($this->buffer[$this->offset]))
{ {
@ -576,7 +575,7 @@ namespace ncc\ZiProto;
/** /**
* @return int * @return int
*/ */
private function decodeUint16() private function decodeUint16(): int
{ {
if (!isset($this->buffer[$this->offset + 1])) if (!isset($this->buffer[$this->offset + 1]))
{ {
@ -593,7 +592,7 @@ namespace ncc\ZiProto;
/** /**
* @return mixed * @return mixed
*/ */
private function decodeUint32() private function decodeUint32(): mixed
{ {
if (!isset($this->buffer[$this->offset + 3])) if (!isset($this->buffer[$this->offset + 3]))
{ {
@ -625,7 +624,7 @@ namespace ncc\ZiProto;
/** /**
* @return int * @return int
*/ */
private function decodeInt8() private function decodeInt8(): int
{ {
if (!isset($this->buffer[$this->offset])) if (!isset($this->buffer[$this->offset]))
{ {
@ -641,7 +640,7 @@ namespace ncc\ZiProto;
/** /**
* @return int * @return int
*/ */
private function decodeInt16() private function decodeInt16(): int
{ {
if (!isset($this->buffer[$this->offset + 1])) if (!isset($this->buffer[$this->offset + 1]))
{ {
@ -658,7 +657,7 @@ namespace ncc\ZiProto;
/** /**
* @return int * @return int
*/ */
private function decodeInt32() private function decodeInt32(): int
{ {
if (!isset($this->buffer[$this->offset + 3])) if (!isset($this->buffer[$this->offset + 3]))
{ {
@ -674,7 +673,7 @@ namespace ncc\ZiProto;
/** /**
* @return mixed * @return mixed
*/ */
private function decodeInt64() private function decodeInt64(): mixed
{ {
if (!isset($this->buffer[$this->offset + 7])) if (!isset($this->buffer[$this->offset + 7]))
{ {
@ -690,7 +689,7 @@ namespace ncc\ZiProto;
/** /**
* @return mixed * @return mixed
*/ */
private function decodeFloat32() private function decodeFloat32(): mixed
{ {
if (!isset($this->buffer[$this->offset + 3])) if (!isset($this->buffer[$this->offset + 3]))
{ {
@ -706,7 +705,7 @@ namespace ncc\ZiProto;
/** /**
* @return mixed * @return mixed
*/ */
private function decodeFloat64() private function decodeFloat64(): mixed
{ {
if (!isset($this->buffer[$this->offset + 7])) if (!isset($this->buffer[$this->offset + 7]))
{ {
@ -723,7 +722,7 @@ namespace ncc\ZiProto;
* @param $length * @param $length
* @return string * @return string
*/ */
private function decodeStrData($length) private function decodeStrData($length): string
{ {
if (!isset($this->buffer[$this->offset + $length - 1])) if (!isset($this->buffer[$this->offset + $length - 1]))
{ {
@ -740,7 +739,7 @@ namespace ncc\ZiProto;
* @param $size * @param $size
* @return array * @return array
*/ */
private function decodeArrayData($size) private function decodeArrayData($size): array
{ {
$array = []; $array = [];
@ -756,7 +755,7 @@ namespace ncc\ZiProto;
* @param $size * @param $size
* @return array * @return array
*/ */
private function decodeMapData($size) private function decodeMapData($size): array
{ {
$map = []; $map = [];
@ -772,7 +771,7 @@ namespace ncc\ZiProto;
* @param $length * @param $length
* @return mixed|Ext * @return mixed|Ext
*/ */
private function decodeExtData($length) private function decodeExtData($length): mixed
{ {
if (!isset($this->buffer[$this->offset + $length - 1])) if (!isset($this->buffer[$this->offset + $length - 1]))
{ {
@ -801,12 +800,12 @@ namespace ncc\ZiProto;
*/ */
private function handleIntOverflow($value) private function handleIntOverflow($value)
{ {
if ($this->isBigIntAsStr) if ($this->big_int_as_str)
{ {
return sprintf('%u', $value); return sprintf('%u', $value);
} }
if ($this->isBigIntAsGmp) if ($this->big_int_as_gmp)
{ {
return gmp_init(sprintf('%u', $value)); return gmp_init(sprintf('%u', $value));
} }

View file

@ -1,29 +1,32 @@
<?php <?php
/*
* Copyright (c) Nosial 2022-2023, all rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, including without
* limitation the rights 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:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
namespace ncc\ZiProto; /** @noinspection PhpMissingFieldTypeInspection */
use ncc\ZiProto\Exception\InvalidOptionException; /*
use ncc\ZiProto\Abstracts\Options; * Copyright (c) Nosial 2022-2023, all rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, including without
* limitation the rights 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:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
namespace ncc\Extensions\ZiProto;
use ncc\Extensions\ZiProto\Exception\InvalidOptionException;
use ncc\Extensions\ZiProto\Abstracts\Options;
/** /**
* Class DecodingOptions * Class DecodingOptions
@ -33,9 +36,9 @@ namespace ncc\ZiProto;
{ {
/** /**
* @var * @var int
*/ */
private $bigIntMode; private $big_int_mode;
/** /**
* DecodingOptions constructor. * DecodingOptions constructor.
@ -48,7 +51,7 @@ namespace ncc\ZiProto;
public static function fromDefaults() : self public static function fromDefaults() : self
{ {
$self = new self(); $self = new self();
$self->bigIntMode = Options::BIGINT_AS_STR; $self->big_int_mode = Options::BIGINT_AS_STR;
return $self; return $self;
} }
@ -61,7 +64,7 @@ namespace ncc\ZiProto;
{ {
$self = new self(); $self = new self();
$self->bigIntMode = self::getSingleOption($bitmask, $self->big_int_mode = self::getSingleOption($bitmask,
Options::BIGINT_AS_STR | Options::BIGINT_AS_STR |
Options::BIGINT_AS_GMP | Options::BIGINT_AS_GMP |
Options::BIGINT_AS_EXCEPTION Options::BIGINT_AS_EXCEPTION
@ -75,7 +78,7 @@ namespace ncc\ZiProto;
*/ */
public function isBigIntAsStrMode() : bool public function isBigIntAsStrMode() : bool
{ {
return Options::BIGINT_AS_STR === $this->bigIntMode; return Options::BIGINT_AS_STR === $this->big_int_mode;
} }
/** /**
@ -83,17 +86,17 @@ namespace ncc\ZiProto;
*/ */
public function isBigIntAsGmpMode() : bool public function isBigIntAsGmpMode() : bool
{ {
return Options::BIGINT_AS_GMP === $this->bigIntMode; return Options::BIGINT_AS_GMP === $this->big_int_mode;
} }
/** /**
* @param int $bitmask * @param int $bitmask
* @param int $validBitmask * @param int $valid_bitmask
* @return int * @return int
*/ */
private static function getSingleOption(int $bitmask, int $validBitmask) : int private static function getSingleOption(int $bitmask, int $valid_bitmask) : int
{ {
$option = $bitmask & $validBitmask; $option = $bitmask & $valid_bitmask;
if ($option === ($option & -$option)) if ($option === ($option & -$option))
{ {
return $option; return $option;
@ -105,12 +108,14 @@ namespace ncc\ZiProto;
Options::BIGINT_AS_EXCEPTION => 'BIGINT_AS_EXCEPTION', Options::BIGINT_AS_EXCEPTION => 'BIGINT_AS_EXCEPTION',
]; ];
$validOptions = []; $valid_options = [];
for ($i = $validBitmask & -$validBitmask; $i <= $validBitmask; $i <<= 1)
/** @noinspection SuspiciousLoopInspection */
for ($i = $valid_bitmask & -$valid_bitmask; $i <= $valid_bitmask; $i <<= 1)
{ {
$validOptions[] = __CLASS__.'::'.$map[$i]; $valid_options[] = __CLASS__.'::'.$map[$i];
} }
throw InvalidOptionException::outOfRange('bigint', $validOptions); throw InvalidOptionException::outOfRange('bigint', $valid_options);
} }
} }

View file

@ -1,29 +1,32 @@
<?php <?php
/*
* Copyright (c) Nosial 2022-2023, all rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, including without
* limitation the rights 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:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
namespace ncc\ZiProto; /** @noinspection PhpMissingFieldTypeInspection */
use ncc\ZiProto\Exception\InvalidOptionException; /*
use ncc\ZiProto\Abstracts\Options; * Copyright (c) Nosial 2022-2023, all rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, including without
* limitation the rights 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:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
namespace ncc\Extensions\ZiProto;
use ncc\Extensions\ZiProto\Exception\InvalidOptionException;
use ncc\Extensions\ZiProto\Abstracts\Options;
/** /**
* Class EncodingOptions * Class EncodingOptions
@ -34,17 +37,17 @@ namespace ncc\ZiProto;
/** /**
* @var mixed * @var mixed
*/ */
private $strBinMode; private $str_bin_mode;
/** /**
* @var mixed * @var mixed
*/ */
private $arrMapMode; private $array_map_mode;
/** /**
* @var mixed * @var mixed
*/ */
private $floatMode; private $float_mode;
/** /**
* EncodingOptions constructor. * EncodingOptions constructor.
@ -57,9 +60,10 @@ namespace ncc\ZiProto;
public static function fromDefaults() : self public static function fromDefaults() : self
{ {
$self = new self(); $self = new self();
$self->strBinMode = Options::DETECT_STR_BIN;
$self->arrMapMode = Options::DETECT_ARR_MAP; $self->str_bin_mode = Options::DETECT_STR_BIN;
$self->floatMode = Options::FORCE_FLOAT64; $self->array_map_mode = Options::DETECT_ARR_MAP;
$self->float_mode = Options::FORCE_FLOAT64;
return $self; return $self;
} }
@ -74,7 +78,7 @@ namespace ncc\ZiProto;
if (self::getSingleOption('str/bin', $bitmask, Options::FORCE_STR | Options::FORCE_BIN | Options::DETECT_STR_BIN)) if (self::getSingleOption('str/bin', $bitmask, Options::FORCE_STR | Options::FORCE_BIN | Options::DETECT_STR_BIN))
{ {
$self->strBinMode = self::getSingleOption('str/bin', $bitmask, $self->str_bin_mode = self::getSingleOption('str/bin', $bitmask,
Options::FORCE_STR | Options::FORCE_STR |
Options::FORCE_BIN | Options::FORCE_BIN |
Options::DETECT_STR_BIN Options::DETECT_STR_BIN
@ -82,12 +86,12 @@ namespace ncc\ZiProto;
} }
else else
{ {
$self->strBinMode = Options::DETECT_STR_BIN; $self->str_bin_mode = Options::DETECT_STR_BIN;
} }
if (self::getSingleOption('arr/map', $bitmask, Options::FORCE_ARR | Options::FORCE_MAP | Options::DETECT_ARR_MAP)) if (self::getSingleOption('arr/map', $bitmask, Options::FORCE_ARR | Options::FORCE_MAP | Options::DETECT_ARR_MAP))
{ {
$self->arrMapMode = self::getSingleOption('arr/map', $bitmask, $self->array_map_mode = self::getSingleOption('arr/map', $bitmask,
Options::FORCE_ARR | Options::FORCE_ARR |
Options::FORCE_MAP | Options::FORCE_MAP |
Options::DETECT_ARR_MAP Options::DETECT_ARR_MAP
@ -95,19 +99,19 @@ namespace ncc\ZiProto;
} }
else else
{ {
$self->arrMapMode = Options::DETECT_ARR_MAP; $self->array_map_mode = Options::DETECT_ARR_MAP;
} }
if (self::getSingleOption('float', $bitmask, Options::FORCE_FLOAT32 | Options::FORCE_FLOAT64)) if (self::getSingleOption('float', $bitmask, Options::FORCE_FLOAT32 | Options::FORCE_FLOAT64))
{ {
$self->floatMode = self::getSingleOption('float', $bitmask, $self->float_mode = self::getSingleOption('float', $bitmask,
Options::FORCE_FLOAT32 | Options::FORCE_FLOAT32 |
Options::FORCE_FLOAT64 Options::FORCE_FLOAT64
); );
} }
else else
{ {
$self->floatMode = Options::FORCE_FLOAT64; $self->float_mode = Options::FORCE_FLOAT64;
} }
return $self; return $self;
@ -118,7 +122,7 @@ namespace ncc\ZiProto;
*/ */
public function isDetectStrBinMode() : bool public function isDetectStrBinMode() : bool
{ {
return Options::DETECT_STR_BIN === $this->strBinMode; return Options::DETECT_STR_BIN === $this->str_bin_mode;
} }
/** /**
@ -126,7 +130,7 @@ namespace ncc\ZiProto;
*/ */
public function isForceStrMode() : bool public function isForceStrMode() : bool
{ {
return Options::FORCE_STR === $this->strBinMode; return Options::FORCE_STR === $this->str_bin_mode;
} }
/** /**
@ -134,7 +138,7 @@ namespace ncc\ZiProto;
*/ */
public function isDetectArrMapMode() : bool public function isDetectArrMapMode() : bool
{ {
return Options::DETECT_ARR_MAP === $this->arrMapMode; return Options::DETECT_ARR_MAP === $this->array_map_mode;
} }
/** /**
@ -142,7 +146,7 @@ namespace ncc\ZiProto;
*/ */
public function isForceArrMode() : bool public function isForceArrMode() : bool
{ {
return Options::FORCE_ARR === $this->arrMapMode; return Options::FORCE_ARR === $this->array_map_mode;
} }
/** /**
@ -150,18 +154,18 @@ namespace ncc\ZiProto;
*/ */
public function isForceFloat32Mode() : bool public function isForceFloat32Mode() : bool
{ {
return Options::FORCE_FLOAT32 === $this->floatMode; return Options::FORCE_FLOAT32 === $this->float_mode;
} }
/** /**
* @param string $name * @param string $name
* @param int $bitmask * @param int $bitmask
* @param int $validBitmask * @param int $valid_bitmask
* @return int * @return int
*/ */
private static function getSingleOption(string $name, int $bitmask, int $validBitmask) : int private static function getSingleOption(string $name, int $bitmask, int $valid_bitmask) : int
{ {
$option = $bitmask & $validBitmask; $option = $bitmask & $valid_bitmask;
if ($option === ($option & -$option)) if ($option === ($option & -$option))
{ {
@ -179,13 +183,14 @@ namespace ncc\ZiProto;
Options::FORCE_FLOAT64 => 'FORCE_FLOAT64', Options::FORCE_FLOAT64 => 'FORCE_FLOAT64',
]; ];
$validOptions = []; $valid_options = [];
for ($i = $validBitmask & -$validBitmask; $i <= $validBitmask; $i <<= 1) /** @noinspection SuspiciousLoopInspection */
for($i = $valid_bitmask & -$valid_bitmask; $i <= $valid_bitmask; $i <<= 1)
{ {
$validOptions[] = __CLASS__.'::'.$map[$i]; $valid_options[] = __CLASS__.'::'.$map[$i];
} }
throw InvalidOptionException::outOfRange($name, $validOptions); throw InvalidOptionException::outOfRange($name, $valid_options);
} }
} }

View file

@ -1,26 +1,26 @@
<?php <?php
/* /*
* Copyright (c) Nosial 2022-2023, all rights reserved. * Copyright (c) Nosial 2022-2023, all rights reserved.
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, including without * associated documentation files (the "Software"), to deal in the Software without restriction, including without
* limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the * limitation the rights 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 * Software, and to permit persons to whom the Software is furnished to do so, subject to the following
* conditions: * conditions:
* *
* The above copyright notice and this permission notice shall be included in all copies or substantial portions * The above copyright notice and this permission notice shall be included in all copies or substantial portions
* of the Software. * of the Software.
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE. * DEALINGS IN THE SOFTWARE.
* *
*/ */
namespace ncc\ZiProto\Exception; namespace ncc\Extensions\ZiProto\Exception;
use RuntimeException; use RuntimeException;
use function sprintf; use function sprintf;

View file

@ -1,26 +1,29 @@
<?php <?php
/*
* Copyright (c) Nosial 2022-2023, all rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, including without
* limitation the rights 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:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
namespace ncc\ZiProto\Exception; /** @noinspection PhpMissingFieldTypeInspection */
/*
* Copyright (c) Nosial 2022-2023, all rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, including without
* limitation the rights 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:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
namespace ncc\Extensions\ZiProto\Exception;
use function get_class; use function get_class;
use function gettype; use function gettype;
@ -46,7 +49,7 @@ namespace ncc\ZiProto\Exception;
* @param string $message * @param string $message
* @param Throwable|null $previous * @param Throwable|null $previous
*/ */
public function __construct($value, string $message = '', Throwable $previous = null) public function __construct($value, string $message='', Throwable $previous=null)
{ {
parent::__construct($message, 0, $previous); parent::__construct($message, 0, $previous);
$this->value = $value; $this->value = $value;
@ -55,7 +58,7 @@ namespace ncc\ZiProto\Exception;
/** /**
* @return mixed * @return mixed
*/ */
public function getValue() public function getValue(): mixed
{ {
return $this->value; return $this->value;
} }

View file

@ -1,26 +1,26 @@
<?php <?php
/* /*
* Copyright (c) Nosial 2022-2023, all rights reserved. * Copyright (c) Nosial 2022-2023, all rights reserved.
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, including without * associated documentation files (the "Software"), to deal in the Software without restriction, including without
* limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the * limitation the rights 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 * Software, and to permit persons to whom the Software is furnished to do so, subject to the following
* conditions: * conditions:
* *
* The above copyright notice and this permission notice shall be included in all copies or substantial portions * The above copyright notice and this permission notice shall be included in all copies or substantial portions
* of the Software. * of the Software.
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE. * DEALINGS IN THE SOFTWARE.
* *
*/ */
namespace ncc\ZiProto\Exception; namespace ncc\Extensions\ZiProto\Exception;
use function strlen; use function strlen;
@ -33,13 +33,13 @@ namespace ncc\ZiProto\Exception;
/** /**
* @param string $buffer * @param string $buffer
* @param int $offset * @param int $offset
* @param int $expectedLength * @param int $expected_length
* @return InsufficientDataException * @return InsufficientDataException
*/ */
public static function unexpectedLength(string $buffer, int $offset, int $expectedLength) : self public static function unexpectedLength(string $buffer, int $offset, int $expected_length) : self
{ {
$actualLength = strlen($buffer) - $offset; $actual_length = strlen($buffer) - $offset;
$message = "Not enough data to unpack: expected $expectedLength, got $actualLength."; $message = "Not enough data to unpack: expected $expected_length, got $actual_length.";
return new self($message); return new self($message);
} }
} }

View file

@ -1,26 +1,29 @@
<?php <?php
/*
* Copyright (c) Nosial 2022-2023, all rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, including without
* limitation the rights 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:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
namespace ncc\ZiProto\Exception; /** @noinspection PhpMissingFieldTypeInspection */
/*
* Copyright (c) Nosial 2022-2023, all rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, including without
* limitation the rights 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:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
namespace ncc\Extensions\ZiProto\Exception;
use function sprintf; use function sprintf;

View file

@ -1,26 +1,26 @@
<?php <?php
/* /*
* Copyright (c) Nosial 2022-2023, all rights reserved. * Copyright (c) Nosial 2022-2023, all rights reserved.
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, including without * associated documentation files (the "Software"), to deal in the Software without restriction, including without
* limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the * limitation the rights 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 * Software, and to permit persons to whom the Software is furnished to do so, subject to the following
* conditions: * conditions:
* *
* The above copyright notice and this permission notice shall be included in all copies or substantial portions * The above copyright notice and this permission notice shall be included in all copies or substantial portions
* of the Software. * of the Software.
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE. * DEALINGS IN THE SOFTWARE.
* *
*/ */
namespace ncc\ZiProto\Exception; namespace ncc\Extensions\ZiProto\Exception;
use function array_pop; use function array_pop;
use function count; use function count;
@ -35,15 +35,15 @@ namespace ncc\ZiProto\Exception;
class InvalidOptionException extends InvalidArgumentException class InvalidOptionException extends InvalidArgumentException
{ {
/** /**
* @param string $invalidOption * @param string $invalid_option
* @param array $validOptions * @param array $valid_options
* @return InvalidOptionException * @return InvalidOptionException
*/ */
public static function outOfRange(string $invalidOption, array $validOptions) : self public static function outOfRange(string $invalid_option, array $valid_options) : self
{ {
$use = count($validOptions) > 2 $use = count($valid_options) > 2
? sprintf('one of %2$s or %1$s', array_pop($validOptions), implode(', ', $validOptions)) ? sprintf('one of %2$s or %1$s', array_pop($valid_options), implode(', ', $valid_options))
: implode(' or ', $validOptions); : implode(' or ', $valid_options);
return new self("Invalid option $invalidOption, use $use."); return new self("Invalid option $invalid_option, use $use.");
} }
} }

View file

@ -1,45 +1,45 @@
<?php <?php
/*
* Copyright (c) Nosial 2022-2023, all rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, including without
* limitation the rights 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:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
namespace ncc\ZiProto; /** @noinspection PhpMissingFieldTypeInspection */
/** /*
* Class Ext * Copyright (c) Nosial 2022-2023, all rights reserved.
* @package ZiProto *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, including without
* limitation the rights 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:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/ */
namespace ncc\Extensions\ZiProto;
final class Ext final class Ext
{ {
/** /**
* @var int * @var int
*/ */
public $type; private $type;
/** /**
* @var string * @var string
*/ */
public $data; private $data;
/** /**
* Ext constructor. * Ext constructor.
*
* @param int $type * @param int $type
* @param string $data * @param string $data
*/ */
@ -48,4 +48,20 @@ namespace ncc\ZiProto;
$this->type = $type; $this->type = $type;
$this->data = $data; $this->data = $data;
} }
/**
* @return int
*/
public function getType(): int
{
return $this->type;
}
/**
* @return string
*/
public function getData(): string
{
return $this->data;
}
} }

View file

@ -1,27 +1,31 @@
<?php <?php
/*
* Copyright (c) Nosial 2022-2023, all rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, including without
* limitation the rights 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:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
namespace ncc\ZiProto; /** @noinspection PhpMissingFieldTypeInspection */
/*
* Copyright (c) Nosial 2022-2023, all rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, including without
* limitation the rights 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:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
namespace ncc\Extensions\ZiProto;
use JsonSerializable;
use function array_values; use function array_values;
use function chr; use function chr;
use function count; use function count;
@ -33,10 +37,10 @@ namespace ncc\ZiProto;
use function pack; use function pack;
use function preg_match; use function preg_match;
use function strlen; use function strlen;
use ncc\ZiProto\Abstracts\Regex; use ncc\Extensions\ZiProto\Abstracts\Regex;
use ncc\ZiProto\Exception\InvalidOptionException; use ncc\Extensions\ZiProto\Exception\InvalidOptionException;
use ncc\ZiProto\Exception\EncodingFailedException; use ncc\Extensions\ZiProto\Exception\EncodingFailedException;
use ncc\ncc\ZiProto\TypeTransformer\Validator; use ncc\Extensions\ZiProto\TypeTransformer\Validator;
/** /**
* Class Packet * Class Packet
@ -47,41 +51,43 @@ namespace ncc\ZiProto;
/** /**
* @var bool * @var bool
*/ */
private $isDetectStrBin; private $bin_mode;
/** /**
* @var bool * @var bool
*/ */
private $isForceStr; private $force_string;
/** /**
* @var bool * @var bool
*/ */
private $isDetectArrMap; private $detect_array_map;
/** /**
* @var bool * @var bool
*/ */
private $isForceArr; private $force_array;
/** /**
* @var bool * @var bool
*/ */
private $isForceFloat32; private $force_float32;
/** /**
* @var Validator[]|null * @var Validator[]
*/ */
private $transformers; private $transformers;
/** /**
* @param EncodingOptions|int|null $options * Packet constructor.
* *
* @param int|EncodingOptions|null $options
* @see EncodingOptions
* @throws InvalidOptionException * @throws InvalidOptionException
*/ */
public function __construct($options = null) public function __construct(int|EncodingOptions|null $options=null)
{ {
if (null === $options) if ($options === null)
{ {
$options = EncodingOptions::fromDefaults(); $options = EncodingOptions::fromDefaults();
} }
@ -90,21 +96,23 @@ namespace ncc\ZiProto;
$options = EncodingOptions::fromBitmask($options); $options = EncodingOptions::fromBitmask($options);
} }
$this->isDetectStrBin = $options->isDetectStrBinMode(); $this->bin_mode = $options->isDetectStrBinMode();
$this->isForceStr = $options->isForceStrMode(); $this->force_string = $options->isForceStrMode();
$this->isDetectArrMap = $options->isDetectArrMapMode(); $this->detect_array_map = $options->isDetectArrMapMode();
$this->isForceArr = $options->isForceArrMode(); $this->force_array = $options->isForceArrMode();
$this->isForceFloat32 = $options->isForceFloat32Mode(); $this->force_float32 = $options->isForceFloat32Mode();
$this->transformers = [];
} }
/** /**
* Registers a transformer.
*
* @param Validator $transformer * @param Validator $transformer
* @return Packet * @return Packet
*/ */
public function registerTransformer(Validator $transformer) : self public function registerTransformer(Validator $transformer): self
{ {
$this->transformers[] = $transformer; $this->transformers[] = $transformer;
return $this; return $this;
} }
@ -121,12 +129,12 @@ namespace ncc\ZiProto;
if (is_string($value)) if (is_string($value))
{ {
if ($this->isForceStr) if ($this->force_string)
{ {
return $this->encodeStr($value); return $this->encodeStr($value);
} }
if ($this->isDetectStrBin) if ($this->bin_mode)
{ {
return preg_match(Regex::UTF8_REGEX, $value) return preg_match(Regex::UTF8_REGEX, $value)
? $this->encodeStr($value) ? $this->encodeStr($value)
@ -138,14 +146,14 @@ namespace ncc\ZiProto;
if (is_array($value)) if (is_array($value))
{ {
if ($this->isDetectArrMap) if ($this->detect_array_map)
{ {
return array_values($value) === $value return array_values($value) === $value
? $this->encodeArray($value) ? $this->encodeArray($value)
: $this->encodeMap($value); : $this->encodeMap($value);
} }
return $this->isForceArr ? $this->encodeArray($value) : $this->encodeMap($value); return $this->force_array ? $this->encodeArray($value) : $this->encodeMap($value);
} }
if (null === $value) if (null === $value)
@ -165,7 +173,12 @@ namespace ncc\ZiProto;
if ($value instanceof Ext) if ($value instanceof Ext)
{ {
return $this->encodeExt($value->type, $value->data); return $this->encodeExt($value->getType(), $value->getData());
}
if($value instanceof JsonSerializable)
{
return $this->encode($value->jsonSerialize());
} }
if ($this->transformers) if ($this->transformers)
@ -259,7 +272,7 @@ namespace ncc\ZiProto;
*/ */
public function encodeFloat($float): string public function encodeFloat($float): string
{ {
return $this->isForceFloat32 return $this->force_float32
? "\xca". pack('G', $float) ? "\xca". pack('G', $float)
: "\xcb". pack('E', $float); : "\xcb". pack('E', $float);
} }
@ -354,7 +367,7 @@ namespace ncc\ZiProto;
{ {
$data = $this->encodeMapHeader(count($map)); $data = $this->encodeMapHeader(count($map));
if ($this->isForceStr) if ($this->force_string)
{ {
foreach ($map as $key => $val) foreach ($map as $key => $val)
{ {
@ -365,7 +378,7 @@ namespace ncc\ZiProto;
return $data; return $data;
} }
if ($this->isDetectStrBin) if ($this->bin_mode)
{ {
foreach ($map as $key => $val) foreach ($map as $key => $val)
{ {

View file

@ -1,26 +1,29 @@
<?php <?php
/*
* Copyright (c) Nosial 2022-2023, all rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, including without
* limitation the rights 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:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
namespace ncc\ZiProto\Type; /** @noinspection PhpMissingFieldTypeInspection */
/*
* Copyright (c) Nosial 2022-2023, all rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, including without
* limitation the rights 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:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
namespace ncc\Extensions\ZiProto\Type;
/** /**
* Class Binary * Class Binary
@ -31,7 +34,7 @@ namespace ncc\ZiProto\Type;
/** /**
* @var string * @var string
*/ */
public $data; private $data;
/** /**
* Binary constructor. * Binary constructor.
@ -41,4 +44,12 @@ namespace ncc\ZiProto\Type;
{ {
$this->data = $data; $this->data = $data;
} }
/**
* @return string
*/
public function getData(): string
{
return $this->data;
}
} }

View file

@ -1,26 +1,29 @@
<?php <?php
/*
* Copyright (c) Nosial 2022-2023, all rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, including without
* limitation the rights 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:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
namespace ncc\ZiProto\Type; /** @noinspection PhpMissingFieldTypeInspection */
/*
* Copyright (c) Nosial 2022-2023, all rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, including without
* limitation the rights 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:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
namespace ncc\Extensions\ZiProto\Type;
/** /**
* Class Map * Class Map
@ -31,7 +34,7 @@ namespace ncc\ZiProto\Type;
/** /**
* @var array * @var array
*/ */
public $map; private $map;
/** /**
* Map constructor. * Map constructor.
@ -41,4 +44,12 @@ namespace ncc\ZiProto\Type;
{ {
$this->map = $map; $this->map = $map;
} }
/**
* @return array
*/
public function getMap(): array
{
return $this->map;
}
} }

View file

@ -1,29 +1,29 @@
<?php <?php
/* /*
* Copyright (c) Nosial 2022-2023, all rights reserved. * Copyright (c) Nosial 2022-2023, all rights reserved.
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, including without * associated documentation files (the "Software"), to deal in the Software without restriction, including without
* limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the * limitation the rights 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 * Software, and to permit persons to whom the Software is furnished to do so, subject to the following
* conditions: * conditions:
* *
* The above copyright notice and this permission notice shall be included in all copies or substantial portions * The above copyright notice and this permission notice shall be included in all copies or substantial portions
* of the Software. * of the Software.
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE. * DEALINGS IN THE SOFTWARE.
* *
*/ */
namespace ncc\ncc\ZiProto\TypeTransformer; namespace ncc\Extensions\ZiProto\TypeTransformer;
use ncc\ZiProto\Packet; use ncc\Extensions\ZiProto\Packet;
use ncc\ZiProto\Type\Binary; use ncc\Extensions\ZiProto\Type\Binary;
/** /**
* Class BinaryTransformer * Class BinaryTransformer
@ -40,7 +40,7 @@ namespace ncc\ncc\ZiProto\TypeTransformer;
{ {
if ($value instanceof Binary) if ($value instanceof Binary)
{ {
return $packer->encodeBin($value->data); return $packer->encodeBin($value->getData());
} }
return null; return null;

View file

@ -1,28 +1,28 @@
<?php <?php
/* /*
* Copyright (c) Nosial 2022-2023, all rights reserved. * Copyright (c) Nosial 2022-2023, all rights reserved.
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, including without * associated documentation files (the "Software"), to deal in the Software without restriction, including without
* limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the * limitation the rights 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 * Software, and to permit persons to whom the Software is furnished to do so, subject to the following
* conditions: * conditions:
* *
* The above copyright notice and this permission notice shall be included in all copies or substantial portions * The above copyright notice and this permission notice shall be included in all copies or substantial portions
* of the Software. * of the Software.
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE. * DEALINGS IN THE SOFTWARE.
* *
*/ */
namespace ncc\ncc\ZiProto\TypeTransformer; namespace ncc\Extensions\ZiProto\TypeTransformer;
use ncc\ZiProto\BufferStream; use ncc\Extensions\ZiProto\BufferStream;
/** /**
* Interface Extension * Interface Extension

View file

@ -1,29 +1,29 @@
<?php <?php
/* /*
* Copyright (c) Nosial 2022-2023, all rights reserved. * Copyright (c) Nosial 2022-2023, all rights reserved.
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, including without * associated documentation files (the "Software"), to deal in the Software without restriction, including without
* limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the * limitation the rights 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 * Software, and to permit persons to whom the Software is furnished to do so, subject to the following
* conditions: * conditions:
* *
* The above copyright notice and this permission notice shall be included in all copies or substantial portions * The above copyright notice and this permission notice shall be included in all copies or substantial portions
* of the Software. * of the Software.
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE. * DEALINGS IN THE SOFTWARE.
* *
*/ */
namespace ncc\ZiProto\TypeTransformer; namespace ncc\Extensions\ZiProto\TypeTransformer;
use ncc\ZiProto\Packet; use ncc\Extensions\ZiProto\Packet;
use ncc\ZiProto\Type\Map; use ncc\Extensions\ZiProto\Type\Map;
/** /**
* Class MapTransformer * Class MapTransformer
@ -40,7 +40,7 @@ namespace ncc\ZiProto\TypeTransformer;
{ {
if ($value instanceof Map) if ($value instanceof Map)
{ {
return $packer->encodeMap($value->map); return $packer->encodeMap($value->getMap());
} }
return null; return null;

View file

@ -1,28 +1,28 @@
<?php <?php
/* /*
* Copyright (c) Nosial 2022-2023, all rights reserved. * Copyright (c) Nosial 2022-2023, all rights reserved.
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, including without * associated documentation files (the "Software"), to deal in the Software without restriction, including without
* limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the * limitation the rights 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 * Software, and to permit persons to whom the Software is furnished to do so, subject to the following
* conditions: * conditions:
* *
* The above copyright notice and this permission notice shall be included in all copies or substantial portions * The above copyright notice and this permission notice shall be included in all copies or substantial portions
* of the Software. * of the Software.
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE. * DEALINGS IN THE SOFTWARE.
* *
*/ */
namespace ncc\ncc\ZiProto\TypeTransformer; namespace ncc\Extensions\ZiProto\TypeTransformer;
use ncc\ZiProto\Packet; use ncc\Extensions\ZiProto\Packet;
/** /**
* Interface Validator * Interface Validator

View file

@ -1,30 +1,30 @@
<?php <?php
/* /*
* Copyright (c) Nosial 2022-2023, all rights reserved. * Copyright (c) Nosial 2022-2023, all rights reserved.
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, including without * associated documentation files (the "Software"), to deal in the Software without restriction, including without
* limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the * limitation the rights 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 * Software, and to permit persons to whom the Software is furnished to do so, subject to the following
* conditions: * conditions:
* *
* The above copyright notice and this permission notice shall be included in all copies or substantial portions * The above copyright notice and this permission notice shall be included in all copies or substantial portions
* of the Software. * of the Software.
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE. * DEALINGS IN THE SOFTWARE.
* *
*/ */
namespace ncc\ZiProto; namespace ncc\Extensions\ZiProto;
use ncc\ZiProto\Exception\DecodingFailedException; use Exception;
use ncc\ZiProto\Exception\EncodingFailedException; use InvalidArgumentException;
use ncc\ZiProto\Exception\InvalidOptionException; use JsonSerializable;
/** /**
* ZiProto Class * ZiProto Class
@ -35,30 +35,42 @@ namespace ncc\ZiProto;
class ZiProto class ZiProto
{ {
/** /**
* Encodes the given value to a msgpack string.
*
* @param mixed $value * @param mixed $value
* @param EncodingOptions|int|null $options * @param int|null $options
* * @see EncodingOptions
* @throws InvalidOptionException
* @throws EncodingFailedException
*
* @return string * @return string
*/ */
public static function encode($value, $options = null) : string public static function encode(mixed $value, ?int $options=null) : string
{ {
return (new Packet($options))->encode($value); try
{
return (new Packet($options))->encode($value);
}
catch(Exception $e)
{
throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
}
} }
/** /**
* Decodes the given msgpack string.
*
* @param string $data * @param string $data
* @param DecodingOptions|int|null $options * @param int|null $options
* * @see DecodingOptions
* @throws InvalidOptionException * @return array|bool|int|mixed|Ext|resource|string|null
* @throws DecodingFailedException
*
* @return mixed
*/ */
public static function decode(string $data, $options = null) public static function decode(string $data, ?int $options=null): mixed
{ {
return (new BufferStream($data, $options))->decode(); try
{
return (new BufferStream($data, $options))->decode();
}
catch(Exception $e)
{
throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
}
} }
} }

View file

@ -26,6 +26,7 @@
use ncc\Exceptions\BuildException; use ncc\Exceptions\BuildException;
use ncc\Exceptions\IOException; use ncc\Exceptions\IOException;
use ncc\Exceptions\PathNotFoundException; use ncc\Exceptions\PathNotFoundException;
use ncc\Managers\ProjectManager;
use ncc\Objects\Package; use ncc\Objects\Package;
use ncc\Objects\ProjectConfiguration; use ncc\Objects\ProjectConfiguration;
@ -34,60 +35,15 @@
/** /**
* Public constructor * Public constructor
* *
* @param ProjectConfiguration $project * @param ProjectManager $project_manager
* @param string $path
*/ */
public function __construct(ProjectConfiguration $project, string $path); public function __construct(ProjectManager $project_manager);
/** /**
* Prepares the package for the build process, this method is called before build() * Builds the project and returns the path to the built package
* *
* @param string $build_configuration The build configuration to use to build the project * @param string $build_configuration
* @return void * @return string
*/ */
public function prepare(string $build_configuration=BuildConfigurationValues::DEFAULT): void; public function build(string $build_configuration=BuildConfigurationValues::DEFAULT): string;
/**
* Executes the compiler process in the correct order and returns the finalized Package object
*
* @return Package|null
* @throws BuildException
* @throws PathNotFoundException
* @throws IOException
*/
public function build(): ?Package;
/**
* Compiles the components of the package
*
* @return void
* @throws PathNotFoundException
* @throws IOException
*/
public function compileComponents(): void;
/**
* Compiles the resources of the package
*
* @return void
* @throws PathNotFoundException
* @throws IOException
*/
public function compileResources(): void;
/**
* Compiles the execution policies of the package
*
* @return void
* @throws PathNotFoundException
* @throws IOException
*/
public function compileExecutionPolicies(): void;
/**
* Returns the current state of the package
*
* @return Package|null
*/
public function getPackage(): ?Package;
} }

View file

@ -29,19 +29,12 @@
interface RunnerInterface interface RunnerInterface
{ {
/** /**
* Processes the ExecutionPolicy * Executes the unit and returns the exit code of the process
* *
* @param string $path * @param ExecutionUnit $unit The execution unit to execute
* @param ExecutionPolicy $policy * @param array $args The arguments to pass to the execution unit
* @return ExecutionUnit * @param bool $local Whether to execute the execution unit locally on disk or from a memory buffer
* @throws IOException * @return int The exit code of the process
*/ */
public static function processUnit(string $path, ExecutionPolicy $policy): ExecutionUnit; public static function executeUnit(ExecutionUnit $unit, array $args=[], bool $local=true): int;
/**
* Returns the file extension to use for the target file
*
* @return string
*/
public static function getFileExtension(): string;
} }

View file

@ -36,7 +36,7 @@
use ncc\Utilities\IO; use ncc\Utilities\IO;
use ncc\Utilities\PathFinder; use ncc\Utilities\PathFinder;
use ncc\Utilities\Resolver; use ncc\Utilities\Resolver;
use ncc\ZiProto\ZiProto; use ncc\Extensions\ZiProto\ZiProto;
class CredentialManager class CredentialManager
{ {

View file

@ -51,7 +51,7 @@
use ncc\Utilities\IO; use ncc\Utilities\IO;
use ncc\Utilities\PathFinder; use ncc\Utilities\PathFinder;
use ncc\Utilities\Resolver; use ncc\Utilities\Resolver;
use ncc\ZiProto\ZiProto; use ncc\Extensions\ZiProto\ZiProto;
use RuntimeException; use RuntimeException;
class ExecutionPointerManager class ExecutionPointerManager

View file

@ -34,7 +34,7 @@
use ncc\Utilities\PathFinder; use ncc\Utilities\PathFinder;
use ncc\Utilities\Resolver; use ncc\Utilities\Resolver;
use ncc\Utilities\RuntimeCache; use ncc\Utilities\RuntimeCache;
use ncc\ZiProto\ZiProto; use ncc\Extensions\ZiProto\ZiProto;
class PackageLockManager class PackageLockManager
{ {

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -25,9 +25,10 @@
namespace ncc\Managers; namespace ncc\Managers;
use ncc\Classes\PhpExtension\ExecutableCompiler;
use ncc\Classes\PhpExtension\NccCompiler; use ncc\Classes\PhpExtension\NccCompiler;
use ncc\Classes\PhpExtension\PhpCliTemplate; use ncc\Classes\PhpExtension\Templates\CliTemplate;
use ncc\Classes\PhpExtension\PhpLibraryTemplate; use ncc\Classes\PhpExtension\Templates\LibraryTemplate;
use ncc\Enums\BuildOutputType; use ncc\Enums\BuildOutputType;
use ncc\Enums\CompilerExtensions; use ncc\Enums\CompilerExtensions;
use ncc\Enums\ComponentFileExtensions; use ncc\Enums\ComponentFileExtensions;
@ -155,8 +156,10 @@
return match (strtolower($this->project_configuration->getProject()->getCompiler()->getExtension())) return match (strtolower($this->project_configuration->getProject()->getCompiler()->getExtension()))
{ {
CompilerExtensions::PHP => match (strtolower($configuration->getBuildType())) { CompilerExtensions::PHP => match (strtolower($configuration->getBuildType()))
{
BuildOutputType::NCC_PACKAGE => (new NccCompiler($this))->build($build_configuration), BuildOutputType::NCC_PACKAGE => (new NccCompiler($this))->build($build_configuration),
BuildOutputType::EXECUTABLE => (new ExecutableCompiler($this))->build($build_configuration),
default => throw new BuildException(sprintf('php cannot produce the build type \'%s\'', $configuration->getBuildType())), default => throw new BuildException(sprintf('php cannot produce the build type \'%s\'', $configuration->getBuildType())),
}, },
default => throw new NotSupportedException(sprintf('The compiler extension \'%s\' is not supported', $this->project_configuration->getProject()->getCompiler()->getExtension())), default => throw new NotSupportedException(sprintf('The compiler extension \'%s\' is not supported', $this->project_configuration->getProject()->getCompiler()->getExtension())),
@ -178,11 +181,11 @@
switch(strtolower($template_name)) switch(strtolower($template_name))
{ {
case ProjectTemplates::PHP_CLI: case ProjectTemplates::PHP_CLI:
PhpCliTemplate::applyTemplate($this); CliTemplate::applyTemplate($this);
break; break;
case ProjectTemplates::PHP_LIBRARY: case ProjectTemplates::PHP_LIBRARY:
PhpLibraryTemplate::applyTemplate($this); LibraryTemplate::applyTemplate($this);
break; break;
default: default:
@ -283,7 +286,6 @@
{ {
$configuration = $this->project_configuration->getBuild()->getBuildConfiguration($build_configuration); $configuration = $this->project_configuration->getBuild()->getBuildConfiguration($build_configuration);
/** @noinspection ArrayMergeMissUseInspection */
return array_merge( return array_merge(
$configuration->getDefineConstants(), $configuration->getDefineConstants(),
$this->project_configuration->getBuild()->getDefineConstants() $this->project_configuration->getBuild()->getDefineConstants()
@ -301,7 +303,6 @@
{ {
$configuration = $this->project_configuration->getBuild()->getBuildConfiguration($build_configuration); $configuration = $this->project_configuration->getBuild()->getBuildConfiguration($build_configuration);
/** @noinspection ArrayMergeMissUseInspection */
return array_merge( return array_merge(
$configuration->getOptions(), $configuration->getOptions(),
$this->project_configuration->getBuild()->getOptions() $this->project_configuration->getBuild()->getOptions()
@ -314,7 +315,7 @@
* @param string $project_path The directory for the project to be initialized in * @param string $project_path The directory for the project to be initialized in
* @param string $name The name of the project eg; ProjectLib * @param string $name The name of the project eg; ProjectLib
* @param string $package The standard package name eg; com.example.project * @param string $package The standard package name eg; com.example.project
* @param Compiler $compiler The compiler to use for this project * @param string $compiler The compiler to use for this project
* @param array $options An array of options to use when initializing the project * @param array $options An array of options to use when initializing the project
* @return ProjectManager * @return ProjectManager
* @throws ConfigurationException * @throws ConfigurationException

View file

@ -30,7 +30,7 @@
use ncc\Objects\DefinedRemoteSource; use ncc\Objects\DefinedRemoteSource;
use ncc\Utilities\IO; use ncc\Utilities\IO;
use ncc\Utilities\PathFinder; use ncc\Utilities\PathFinder;
use ncc\ZiProto\ZiProto; use ncc\Extensions\ZiProto\ZiProto;
class RemoteSourcesManager class RemoteSourcesManager
{ {

View file

@ -34,7 +34,7 @@
use ncc\Utilities\IO; use ncc\Utilities\IO;
use ncc\Utilities\PathFinder; use ncc\Utilities\PathFinder;
use ncc\Utilities\Resolver; use ncc\Utilities\Resolver;
use ncc\ZiProto\ZiProto; use ncc\Extensions\ZiProto\ZiProto;
class SymlinkManager class SymlinkManager
{ {

View file

@ -35,7 +35,6 @@
use ncc\Objects\Package\Component; use ncc\Objects\Package\Component;
use ncc\Objects\Package\ExecutionUnit; use ncc\Objects\Package\ExecutionUnit;
use ncc\Objects\Package\Metadata; use ncc\Objects\Package\Metadata;
use ncc\Objects\Package\Installer;
use ncc\Objects\Package\MagicBytes; use ncc\Objects\Package\MagicBytes;
use ncc\Objects\Package\Resource; use ncc\Objects\Package\Resource;
use ncc\Objects\ProjectConfiguration\Assembly; use ncc\Objects\ProjectConfiguration\Assembly;
@ -43,7 +42,7 @@
use ncc\Objects\ProjectConfiguration\Dependency; use ncc\Objects\ProjectConfiguration\Dependency;
use ncc\Utilities\Functions; use ncc\Utilities\Functions;
use ncc\Utilities\IO; use ncc\Utilities\IO;
use ncc\ZiProto\ZiProto; use ncc\Extensions\ZiProto\ZiProto;
class Package implements BytecodeObjectInterface class Package implements BytecodeObjectInterface
{ {
@ -75,13 +74,6 @@
*/ */
private $dependencies; private $dependencies;
/**
* The installer object that is used to install the package if the package is install-able
*
* @var Installer|null
*/
private $installer;
/** /**
* An array of execution units defined in the package * An array of execution units defined in the package
* *

View file

@ -24,10 +24,17 @@
namespace ncc\Objects\Package; namespace ncc\Objects\Package;
use Exception;
use ncc\Classes\PhpExtension\AstWalker;
use ncc\Enums\ComponentDataType; use ncc\Enums\ComponentDataType;
use ncc\Enums\Flags\ComponentFlags;
use ncc\Enums\Options\ComponentDecodeOptions;
use ncc\Exceptions\ConfigurationException; use ncc\Exceptions\ConfigurationException;
use ncc\Extensions\ZiProto\ZiProto;
use ncc\Interfaces\BytecodeObjectInterface; use ncc\Interfaces\BytecodeObjectInterface;
use ncc\ThirdParty\nikic\PhpParser\PrettyPrinter\Standard;
use ncc\Utilities\Functions; use ncc\Utilities\Functions;
use RuntimeException;
class Component implements BytecodeObjectInterface class Component implements BytecodeObjectInterface
{ {
@ -162,11 +169,63 @@
} }
/** /**
* Returns the decoded data of the component, this will decode the data based on the data type and flags of the
* component.
*
* @param array $options
* @return string * @return string
*/ */
public function getData(): string public function getData(array $options=[]): string
{ {
return $this->data; switch($this->data_type)
{
case ComponentDataType::PLAIN:
case ComponentDataType::BINARY:
return $this->data;
case ComponentDataType::BASE64_ENCODED:
if(in_array(ComponentFlags::PHP_B64, $this->flags, true))
{
try
{
if(in_array(ComponentDecodeOptions::AS_FILE, $options, true))
{
return (new Standard())->prettyPrintFile(AstWalker::decodeRecursive(base64_decode($this->data)));
}
return (new Standard())->prettyPrint(AstWalker::decodeRecursive(base64_decode($this->data)));
}
catch(Exception $e)
{
throw new RuntimeException(sprintf('Failed to decode component %s with data type %s because the component is corrupted: %s', $this->name, ComponentFlags::PHP_B64, $e->getMessage()), $e->getCode(), $e);
}
}
return base64_decode($this->data);
case ComponentDataType::AST:
if(in_array(ComponentFlags::PHP_AST, $this->flags, true))
{
try
{
if(in_array(ComponentDecodeOptions::AS_FILE, $options, true))
{
return (new Standard())->prettyPrintFile(AstWalker::decodeRecursive(ZiProto::decode($this->data)));
}
return (new Standard())->prettyPrint(AstWalker::decodeRecursive(ZiProto::decode($this->data)));
}
catch(Exception $e)
{
throw new RuntimeException(sprintf('Failed to decode component %s with data type %s because the component is corrupted: %s', $this->name, ComponentFlags::PHP_AST, $e->getMessage()), $e->getCode(), $e);
}
}
throw new RuntimeException(sprintf('Cannot decode component %s with data type %s because the component does not have a flag to decode it properly', $this->name, 'AST'));
default:
throw new RuntimeException(sprintf('Unknown component data type "%s"', $this->data_type));
}
} }
/** /**

View file

@ -1,24 +1,24 @@
<?php <?php
/* /*
* Copyright (c) Nosial 2022-2023, all rights reserved. * Copyright (c) Nosial 2022-2023, all rights reserved.
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, including without * associated documentation files (the "Software"), to deal in the Software without restriction, including without
* limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the * limitation the rights 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 * Software, and to permit persons to whom the Software is furnished to do so, subject to the following
* conditions: * conditions:
* *
* The above copyright notice and this permission notice shall be included in all copies or substantial portions * The above copyright notice and this permission notice shall be included in all copies or substantial portions
* of the Software. * of the Software.
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE. * DEALINGS IN THE SOFTWARE.
* *
*/ */
/** @noinspection PhpMissingFieldTypeInspection */ /** @noinspection PhpMissingFieldTypeInspection */
@ -27,6 +27,7 @@
use ncc\Exceptions\ConfigurationException; use ncc\Exceptions\ConfigurationException;
use ncc\Interfaces\BytecodeObjectInterface; use ncc\Interfaces\BytecodeObjectInterface;
use ncc\Objects\ProjectConfiguration\Compiler; use ncc\Objects\ProjectConfiguration\Compiler;
use ncc\Objects\ProjectConfiguration\Installer;
use ncc\Objects\ProjectConfiguration\UpdateSource; use ncc\Objects\ProjectConfiguration\UpdateSource;
use ncc\Utilities\Functions; use ncc\Utilities\Functions;
@ -238,6 +239,8 @@
($bytecode ? Functions::cbc('runtime_constants') : 'runtime_constants') => $this->runtime_constants, ($bytecode ? Functions::cbc('runtime_constants') : 'runtime_constants') => $this->runtime_constants,
($bytecode ? Functions::cbc('compiler_version') : 'compiler_version') => $this->compiler_version, ($bytecode ? Functions::cbc('compiler_version') : 'compiler_version') => $this->compiler_version,
($bytecode ? Functions::cbc('update_source') : 'update_source') => ($this->update_source?->toArray($bytecode)), ($bytecode ? Functions::cbc('update_source') : 'update_source') => ($this->update_source?->toArray($bytecode)),
($bytecode ? Functions::cbc('installer') : 'installer') => ($this->installer?->toArray($bytecode)),
($bytecode ? Functions::cbc('main_execution_policy') : 'main_execution_policy') => $this->main_execution_policy,
($bytecode ? Functions::cbc('options') : 'options') => $this->options, ($bytecode ? Functions::cbc('options') : 'options') => $this->options,
]; ];
} }
@ -259,12 +262,20 @@
$object->compiler_version = Functions::array_bc($data, 'compiler_version'); $object->compiler_version = Functions::array_bc($data, 'compiler_version');
$object->update_source = Functions::array_bc($data, 'update_source'); $object->update_source = Functions::array_bc($data, 'update_source');
$object->options = Functions::array_bc($data, 'options'); $object->options = Functions::array_bc($data, 'options');
$object->update_source = Functions::array_bc($data, 'update_source');
$object->main_execution_policy = Functions::array_bc($data, 'main_execution_policy');
$object->installer = Functions::array_bc($data, 'installer');
if($object->update_source !== null) if($object->update_source !== null)
{ {
$object->update_source = UpdateSource::fromArray($object->update_source); $object->update_source = UpdateSource::fromArray($object->update_source);
} }
if($object->installer !== null)
{
$object->installer = Installer::fromArray($object->installer);
}
return $object; return $object;
} }
} }

View file

@ -24,9 +24,10 @@
namespace ncc\Objects; namespace ncc\Objects;
use InvalidArgumentException;
use ncc\Classes\PackageReader;
use ncc\Enums\Versions; use ncc\Enums\Versions;
use ncc\Exceptions\ConfigurationException; use ncc\Exceptions\ConfigurationException;
use ncc\Exceptions\IOException;
use ncc\Interfaces\BytecodeObjectInterface; use ncc\Interfaces\BytecodeObjectInterface;
use ncc\Objects\PackageLock\PackageEntry; use ncc\Objects\PackageLock\PackageEntry;
use ncc\Utilities\Console; use ncc\Utilities\Console;
@ -53,15 +54,36 @@
* *
* @var PackageEntry[] * @var PackageEntry[]
*/ */
private $packages; private $entries;
/** /**
* Public Constructor * Public Constructor
*/ */
public function __construct() public function __construct(array $entries=[], string $package_lock_version=Versions::PACKAGE_LOCK_VERSION, ?int $last_updated_timestamp=null)
{ {
$this->package_lock_version = Versions::PACKAGE_LOCK_VERSION; $this->entries = $entries;
$this->packages = []; $this->package_lock_version = $package_lock_version;
$this->last_updated_timestamp = $last_updated_timestamp ?? time();
}
/**
* Returns the package lock structure version
*
* @return string
*/
public function getPackageLockVersion(): string
{
return $this->package_lock_version;
}
/**
* Returns the Unix Timestamp for when this package lock file was last updated
*
* @return int
*/
public function getLastUpdatedTimestamp(): int
{
return $this->last_updated_timestamp;
} }
/** /**
@ -76,188 +98,141 @@
} }
/** /**
* @param Package $package * Adds a new PackageEntry to the PackageLock file from a PackageReader
* @param string $install_path *
* @param PackageReader $package_reader
* @return void * @return void
* @throws ConfigurationException * @throws ConfigurationException
*/ */
public function addPackage(Package $package, string $install_path): void public function addPackage(PackageReader $package_reader): void
{ {
Console::outVerbose("Adding package {$package->getAssembly()->getPackage()} to package lock file"); Console::outVerbose("Adding package {$package_reader->getAssembly()->getPackage()} to package lock file");
if(!isset($this->packages[$package->getAssembly()->getPackage()])) if(!$this->entryExists($package_reader->getAssembly()->getPackage()))
{ {
$package_entry = new PackageEntry(); $package_entry = new PackageEntry($package_reader->getAssembly()->getPackage());
$package_entry->addVersion($package, $install_path, true); $package_entry->addVersion($package_reader);
$package_entry->setName($package->getAssembly()->getPackage()); $this->addEntry($package_entry);
$package_entry->setUpdateSource($package->getMetadata()->getUpdateSource());
$this->packages[$package->getAssembly()->getPackage()] = $package_entry;
$this->update();
return; return;
} }
$this->packages[$package->getAssembly()->getPackage()]->setUpdateSource($package->getMetadata()->getUpdateSource()); $package_entry = $this->getEntry($package_reader->getAssembly()->getPackage());
$this->packages[$package->getAssembly()->getPackage()]->addVersion($package, $install_path, true); $package_entry->addVersion($package_reader);
$this->addEntry($package_entry);
}
/**
* Returns True if the package entry exists
*
* @param string $package_name
* @return bool
*/
public function entryExists(string $package_name): bool
{
foreach($this->entries as $entry)
{
if($entry->getName() === $package_name)
{
return true;
}
}
return false;
}
/**
* Returns an existing package entry
*
* @param string $package_name
* @return PackageEntry
*/
public function getEntry(string $package_name): PackageEntry
{
foreach($this->entries as $entry)
{
if($entry->getName() === $package_name)
{
return $entry;
}
}
throw new InvalidArgumentException(sprintf('Package entry %s does not exist', $package_name));
}
/**
* Adds a new package entry to the package lock file
*
* @param PackageEntry $entry
* @param bool $overwrite
* @return void
*/
public function addEntry(PackageEntry $entry, bool $overwrite=true): void
{
if($this->entryExists($entry->getName()))
{
if(!$overwrite)
{
return;
}
$this->removeEntry($entry->getName());
}
$this->update(); $this->update();
$this->entries[] = $entry;
} }
/** /**
* Removes a package version entry, removes the entire entry if there are no installed versions * Removes a package entry from the package lock file
* *
* @param string $package * @param string $package_name
* @param string $version * @return void
* @return bool
*/ */
public function removePackageVersion(string $package, string $version): bool public function removeEntry(string $package_name): void
{ {
Console::outVerbose(sprintf('Removing package %s version %s from package lock file', $package, $version)); foreach($this->entries as $index => $entry)
if(isset($this->packages[$package]))
{ {
$r = $this->packages[$package]->removeVersion($version); if($entry->getName() === $package_name)
// Remove the entire package entry if there's no installed versions
if($r && $this->packages[$package]->getLatestVersion() === null)
{ {
unset($this->packages[$package]); unset($this->entries[$index]);
} $this->update();
return;
$this->update();
return $r;
}
return false;
}
/**
* Removes an entire package entry
*
* @param string $package
* @return bool
* @noinspection PhpUnused
*/
public function removePackage(string $package): bool
{
Console::outVerbose(sprintf('Removing package %s from package lock file', $package));
if(isset($this->packages[$package]))
{
unset($this->packages[$package]);
$this->update();
return true;
}
return false;
}
/**
* Gets an existing package entry, returns null if no such entry exists
*
* @param string $package
* @return PackageEntry|null
*/
public function getPackage(string $package): ?PackageEntry
{
Console::outDebug(sprintf('getting package %s from package lock file', $package));
return $this->packages[$package] ?? null;
}
/**
* Determines if the requested package exists in the package lock
*
* @param string $package
* @param string|null $version
* @return bool
*/
public function packageExists(string $package, ?string $version=null): bool
{
$package_entry = $this->getPackage($package);
if($package_entry === null)
{
return false;
}
if($version !== null)
{
try
{
$version_entry = $package_entry->getVersion($version);
}
catch (IOException $e)
{
unset($e);
return false;
}
if($version_entry === null)
{
return false;
} }
} }
return true;
} }
/** /**
* Returns an array of all packages and their installed versions * Returns an array of package entries
* *
* @return array * @return array
*/ */
public function getPackages(): array public function getEntries(): array
{ {
$results = []; return array_map(static function(PackageEntry $entry) {
return $entry->getName();
foreach($this->packages as $package => $entry) }, $this->entries);
{
$results[$package] = $entry->getVersions();
}
return $results;
} }
/** /**
* Returns the path where the package is installed
*
* @param string $package_name
* @param string $version
* @return string * @return string
*/ */
public function getPackageLockVersion(): string public function getPath(string $package_name, string $version): string
{ {
return $this->package_lock_version; return $this->getEntry($package_name)->getPath($version);
} }
/** /**
* @param string $package_lock_version * @inheritDoc
*/
public function setPackageLockVersion(string $package_lock_version): void
{
$this->package_lock_version = $package_lock_version;
}
/**
* @return int
*/
public function getLastUpdatedTimestamp(): int
{
return $this->last_updated_timestamp;
}
/**
* @param int $last_updated_timestamp
*/
public function setLastUpdatedTimestamp(int $last_updated_timestamp): void
{
$this->last_updated_timestamp = $last_updated_timestamp;
}
/**
* Returns an array representation of the object
*
* @param bool $bytecode
* @return array
*/ */
public function toArray(bool $bytecode=false): array public function toArray(bool $bytecode=false): array
{ {
$package_entries = []; $package_entries = [];
foreach($this->packages as $entry) foreach($this->entries as $entry)
{ {
$package_entries[] = $entry->toArray($bytecode); $package_entries[] = $entry->toArray($bytecode);
} }
@ -265,33 +240,30 @@
return [ return [
($bytecode ? Functions::cbc('package_lock_version') : 'package_lock_version') => $this->package_lock_version, ($bytecode ? Functions::cbc('package_lock_version') : 'package_lock_version') => $this->package_lock_version,
($bytecode ? Functions::cbc('last_updated_timestamp') : 'last_updated_timestamp') => $this->last_updated_timestamp, ($bytecode ? Functions::cbc('last_updated_timestamp') : 'last_updated_timestamp') => $this->last_updated_timestamp,
($bytecode ? Functions::cbc('packages') : 'packages') => $package_entries ($bytecode ? Functions::cbc('entries') : 'entries') => $package_entries
]; ];
} }
/** /**
* Constructs object from an array representation * @inheritDoc
* * @throws ConfigurationException
* @param array $data
* @return static
*/ */
public static function fromArray(array $data): self public static function fromArray(array $data): self
{ {
$object = new self(); $entries_array = Functions::array_bc($data, 'entries') ?? [];
$entries = array_map(static function($entry) {
return PackageEntry::fromArray($entry);
}, $entries_array);
$packages = Functions::array_bc($data, 'packages');
if($packages !== null) $package_lock_version = Functions::array_bc($data, 'package_lock_version') ?? Versions::PACKAGE_LOCK_VERSION;
$last_updated_timestamp = Functions::array_bc($data, 'last_updated_timestamp') ?? time();
if($package_lock_version === null)
{ {
foreach($packages as $_datum) throw new ConfigurationException('Package lock version is missing');
{
$entry = PackageEntry::fromArray($_datum);
$object->packages[$entry->getName()] = $entry;
}
} }
$object->package_lock_version = Functions::array_bc($data, 'package_lock_version'); return new self($entries, $package_lock_version, $last_updated_timestamp);
$object->last_updated_timestamp = Functions::array_bc($data, 'last_updated_timestamp');
return $object;
} }
} }

View file

@ -24,18 +24,23 @@
namespace ncc\Objects\PackageLock; namespace ncc\Objects\PackageLock;
use ncc\Enums\Scopes; use InvalidArgumentException;
use ncc\Classes\PackageReader;
use ncc\Enums\FileDescriptor;
use ncc\Enums\Versions; use ncc\Enums\Versions;
use ncc\Exceptions\ConfigurationException; use ncc\Exceptions\ConfigurationException;
use ncc\Exceptions\IOException; use ncc\Exceptions\IOException;
use ncc\Exceptions\PathNotFoundException;
use ncc\Extensions\ZiProto\ZiProto;
use ncc\Interfaces\BytecodeObjectInterface; use ncc\Interfaces\BytecodeObjectInterface;
use ncc\Objects\Package; use ncc\Objects\Package\Metadata;
use ncc\Objects\ProjectConfiguration\Assembly;
use ncc\Objects\ProjectConfiguration\ExecutionPolicy;
use ncc\Objects\ProjectConfiguration\Installer;
use ncc\Objects\ProjectConfiguration\UpdateSource; use ncc\Objects\ProjectConfiguration\UpdateSource;
use ncc\ThirdParty\jelix\Version\VersionComparator; use ncc\ThirdParty\jelix\Version\VersionComparator;
use ncc\ThirdParty\Symfony\Filesystem\Filesystem;
use ncc\Utilities\Functions; use ncc\Utilities\Functions;
use ncc\Utilities\PathFinder; use ncc\Utilities\IO;
use ncc\Utilities\Resolver;
class PackageEntry implements BytecodeObjectInterface class PackageEntry implements BytecodeObjectInterface
{ {
@ -46,13 +51,6 @@
*/ */
private $name; private $name;
/**
* The latest version of the package entry, this is updated automatically
*
* @var string|null
*/
private $latest_version;
/** /**
* An array of installed versions for this package * An array of installed versions for this package
* *
@ -70,25 +68,114 @@
/** /**
* Public Constructor * Public Constructor
*/ */
public function __construct() public function __construct(string $name, array $versions=[])
{ {
$this->versions = []; $this->name = $name;
$this->versions = $versions;
} }
/** /**
* Searches and returns a version of the package * Returns the name of the package entry
*
* @return string
*/
public function getName(): string
{
return $this->name;
}
/**
* Optional. Returns the update source of the package entry
*
* @return UpdateSource|null
*/
public function getUpdateSource(): ?UpdateSource
{
return $this->update_source;
}
/**
* Returns the path to where the package is installed
* *
* @param string $version * @param string $version
* @param bool $throw_exception * @return string
* @return VersionEntry|null
* @throws IOException
*/ */
public function getVersion(string $version, bool $throw_exception=false): ?VersionEntry public function getPath(string $version): string
{ {
if($version === Versions::LATEST && $this->latest_version !== null) return $this->getVersion($version)->getPath($this->name);
}
/**
* Adds a new version entry to the package, if overwrite is true then
* the entry will be overwritten if it exists, otherwise it will return
* false.
*
* @param PackageReader $package_reader
* @param bool $overwrite
* @return bool
* @throws ConfigurationException
*/
public function addVersion(PackageReader $package_reader, bool $overwrite=false): bool
{
if($this->versionExists($package_reader->getAssembly()->getVersion()))
{ {
/** @noinspection CallableParameterUseCaseInTypeContextInspection */ if(!$overwrite)
$version = $this->latest_version; {
return false;
}
$this->removeVersion($package_reader->getAssembly()->getVersion());
}
$version_entry = new VersionEntry($package_reader->getAssembly()->getVersion());
$version_entry->setMainExecutionPolicy($package_reader->getMetadata()->getMainExecutionPolicy());
//foreach($package_reader->getDependencies() as $dependency)
//{
// TODO: Implement this functionality
//}
foreach($package_reader->getExecutionUnits() as $unit)
{
$version_entry->addExecutionPolicy($package_reader->getExecutionUnit($unit)->getExecutionPolicy());
}
$this->versions[] = $version_entry;
$this->update_source =$package_reader->getMetadata()->getUpdateSource();
return true;
}
/**
* Returns True if the given version exists in the entry
*
* @param string $version
* @return bool
*/
public function versionExists(string $version): bool
{
foreach($this->versions as $versionEntry)
{
if($versionEntry->getVersion() === $version)
{
return true;
}
}
return false;
}
/**
* Returns a version entry by version
*
* @param string $version
* @return VersionEntry
*/
public function getVersion(string $version): VersionEntry
{
if($version === Versions::LATEST)
{
$version = $this->getLatestVersion();
} }
foreach($this->versions as $versionEntry) foreach($this->versions as $versionEntry)
@ -99,20 +186,54 @@
} }
} }
if($throw_exception) throw new InvalidArgumentException(sprintf('Version %s does not exist in package %s', $version, $this->name));
{
throw new IOException(sprintf('Version %s of %s is not installed', $version, $this->name));
}
return null;
} }
/** /**
* Removes version entry from the package * Updates and returns the latest version of this package entry
*
* @return string
*/
private function getLatestVersion(): string
{
$latest_version = null;
foreach($this->versions as $version)
{
$version = $version->getVersion();
if($latest_version === null)
{
$latest_version = $version;
continue;
}
if(VersionComparator::compareVersion($version, $latest_version))
{
$latest_version = $version;
}
}
return $latest_version;
}
/**
* Returns an array of all versions installed
*
* @return array
*/
public function getVersions(): array
{
return array_map(static function(VersionEntry $versionEntry) {
return $versionEntry->getVersion();
}, $this->versions);
}
/**
* Removes version entry from the package entry
* *
* @param string $version * @param string $version
* @return bool * @return bool
* @noinspection PhpUnused
*/ */
public function removeVersion(string $version): bool public function removeVersion(string $version): bool
{ {
@ -133,7 +254,6 @@
if($found_node) if($found_node)
{ {
unset($this->versions[$count]); unset($this->versions[$count]);
$this->updateLatestVersion();
return true; return true;
} }
@ -141,157 +261,121 @@
} }
/** /**
* Adds a new version entry to the package, if overwrite is true then * Returns the assembly of the package entry
* the entry will be overwritten if it exists, otherwise it will return
* false.
* *
* @param Package $package * @param string $version
* @param string $install_path * @return Assembly
* @param bool $overwrite
* @return bool
*/
public function addVersion(Package $package, string $install_path, bool $overwrite=false): bool
{
try
{
if ($this->getVersion($package->getAssembly()->getVersion()) !== null)
{
if(!$overwrite)
{
return false;
}
$this->removeVersion($package->getAssembly()->getVersion());
}
}
catch (IOException $e)
{
unset($e);
}
$version = new VersionEntry();
$version->setVersion($package->getAssembly()->getVersion());
$version->setCompiler($package->getMetadata()->getCompilerExtension());
$version->setExecutionUnits($package->getExecutionUnits());
$version->main_execution_policy = $package->getMainExecutionPolicy();
$version->location = $install_path;
foreach($version->getExecutionUnits() as $unit)
{
$unit->setData(null);
}
foreach($package->getDependencies() as $dependency)
{
$version->addDependency(new DependencyEntry($dependency));
}
$this->versions[] = $version;
$this->updateLatestVersion();
return true;
}
/**
* Updates and returns the latest version of this package entry
*
* @return void
*/
private function updateLatestVersion(): void
{
$latest_version = null;
foreach($this->versions as $version)
{
$version = $version->getVersion();
if($latest_version === null)
{
$latest_version = $version;
continue;
}
if(VersionComparator::compareVersion($version, $latest_version))
{
$latest_version = $version;
}
}
$this->latest_version = $latest_version;
}
/**
* @return string|null
*/
public function getLatestVersion(): ?string
{
return $this->latest_version;
}
/**
* Returns an array of all versions installed
*
* @return array
*/
public function getVersions(): array
{
$r = [];
foreach($this->versions as $version)
{
$r[] = $version->getVersion();
}
return $r;
}
/**
* @return string
* @throws ConfigurationException * @throws ConfigurationException
* @throws IOException
* @throws PathNotFoundException
*/ */
public function getDataPath(): string public function getAssembly(string $version=Versions::LATEST): Assembly
{ {
$path = PathFinder::getPackageDataPath($this->name); $assembly_path = $this->getPath($version) . DIRECTORY_SEPARATOR . FileDescriptor::ASSEMBLY;
if(!is_file($assembly_path))
if(!file_exists($path) && Resolver::resolveScope() === Scopes::SYSTEM)
{ {
$filesystem = new Filesystem(); throw new IOException(sprintf('Assembly file for package %s version %s does not exist (Expected %s)', $this->name, $version, $assembly_path));
$filesystem->mkdir($path);
} }
return $path; return Assembly::fromArray(ZiProto::decode(IO::fread($assembly_path)));
} }
/** /**
* Returns the metadata of the package entry
*
* @param string $version
* @return Metadata
* @throws ConfigurationException
* @throws IOException
* @throws PathNotFoundException
*/
public function getMetadata(string $version=Versions::LATEST): Metadata
{
$metadata_path = $this->getPath($version) . DIRECTORY_SEPARATOR . FileDescriptor::METADATA;
if(!is_file($metadata_path))
{
throw new IOException(sprintf('Metadata file for package %s version %s does not exist (Expected %s)', $this->name, $version, $metadata_path));
}
return Metadata::fromArray(ZiProto::decode(IO::fread($metadata_path)));
}
/**
* Optional. Returns the installer details of the package entry
*
* @param string $version
* @return Installer|null
* @throws IOException
* @throws PathNotFoundException
*/
public function getInstaller(string $version=Versions::LATEST): ?Installer
{
$installer_path = $this->getPath($version) . DIRECTORY_SEPARATOR . FileDescriptor::INSTALLER;
if(!is_file($installer_path))
{
return null;
}
return Installer::fromArray(ZiProto::decode(IO::fread($installer_path)));
}
/**
* Returns the class map of the package entry
*
* @param string $version
* @return array
* @throws IOException
* @throws PathNotFoundException
*/
public function getClassMap(string $version=Versions::LATEST): array
{
$class_map_path = $this->getPath($version) . DIRECTORY_SEPARATOR . FileDescriptor::CLASS_MAP;
if(!is_file($class_map_path))
{
return [];
}
return ZiProto::decode(IO::fread($class_map_path));
}
/**
* Returns the execution policy of the package entry
*
* @param string $policy_name
* @param string $version
* @return ExecutionPolicy
* @throws ConfigurationException
* @throws IOException
* @throws PathNotFoundException
*/
public function getExecutionPolicy(string $policy_name, string $version=Versions::LATEST): ExecutionPolicy
{
$execution_policy_path = $this->getPath($version) . DIRECTORY_SEPARATOR . 'units' . DIRECTORY_SEPARATOR . $policy_name . '.policy';
if(!is_file($execution_policy_path))
{
throw new IOException(sprintf('Execution policy %s for package %s version %s does not exist (Expected %s)', $policy_name, $this->name, $version, $execution_policy_path));
}
return ExecutionPolicy::fromArray(ZiProto::decode(IO::fread($execution_policy_path)));
}
/**
* Returns the path to the execution binary of the package entry of a given policy name
*
* @param string $policy_name
* @param string $version
* @return string * @return string
* @throws IOException
*/ */
public function getName(): string public function getExecutionBinaryPath(string $policy_name, string $version=Versions::LATEST): string
{ {
return $this->name; $execution_binary_path = $this->getPath($version) . DIRECTORY_SEPARATOR . 'units' . DIRECTORY_SEPARATOR . $policy_name;
} if(!is_file($execution_binary_path))
{
throw new IOException(sprintf('Execution binary %s for package %s version %s does not exist (Expected %s)', $policy_name, $this->name, $version, $execution_binary_path));
}
/** return $execution_binary_path;
* @param string $name
*/
public function setName(string $name): void
{
$this->name = $name;
}
/**
* @return UpdateSource|null
*/
public function getUpdateSource(): ?UpdateSource
{
return $this->update_source;
}
/**
* @param UpdateSource|null $update_source
*/
public function setUpdateSource(?UpdateSource $update_source): void
{
$this->update_source = $update_source;
} }
/** /**
@ -311,7 +395,6 @@
return [ return [
($bytecode ? Functions::cbc('name') : 'name') => $this->name, ($bytecode ? Functions::cbc('name') : 'name') => $this->name,
($bytecode ? Functions::cbc('latest_version') : 'latest_version') => $this->latest_version,
($bytecode ? Functions::cbc('versions') : 'versions') => $versions, ($bytecode ? Functions::cbc('versions') : 'versions') => $versions,
($bytecode ? Functions::cbc('update_source') : 'update_source') => ($this->update_source?->toArray($bytecode)), ($bytecode ? Functions::cbc('update_source') : 'update_source') => ($this->update_source?->toArray($bytecode)),
]; ];
@ -322,28 +405,26 @@
* *
* @param array $data * @param array $data
* @return PackageEntry * @return PackageEntry
* @throws ConfigurationException
*/ */
public static function fromArray(array $data): PackageEntry public static function fromArray(array $data): PackageEntry
{ {
$object = new self(); $name = Functions::array_bc($data, 'name');
$raw_versions = Functions::array_bc($data, 'versions') ?? [];
$versions = [];
$object->name = Functions::array_bc($data, 'name'); if($name === null)
$object->latest_version = Functions::array_bc($data, 'latest_version'); {
throw new ConfigurationException('PackageEntry is missing name');
}
foreach($raw_versions as $raw_version)
{
$versions[] = VersionEntry::fromArray($raw_version);
}
$object = new self($name, $versions);
$object->update_source = Functions::array_bc($data, 'update_source'); $object->update_source = Functions::array_bc($data, 'update_source');
$versions = Functions::array_bc($data, 'versions');
if($object->update_source !== null)
{
$object->update_source = UpdateSource::fromArray($object->update_source);
}
if($versions !== null)
{
foreach($versions as $_datum)
{
$object->versions[] = VersionEntry::fromArray($_datum);
}
}
return $object; return $object;
} }

View file

@ -24,11 +24,11 @@
namespace ncc\Objects\PackageLock; namespace ncc\Objects\PackageLock;
use ncc\Exceptions\ConfigurationException;
use ncc\Interfaces\BytecodeObjectInterface; use ncc\Interfaces\BytecodeObjectInterface;
use ncc\Objects\InstallationPaths; use ncc\Objects\ProjectConfiguration\ExecutionPolicy;
use ncc\Objects\Package\ExecutionUnit;
use ncc\Objects\ProjectConfiguration\Compiler;
use ncc\Utilities\Functions; use ncc\Utilities\Functions;
use ncc\Utilities\PathFinder;
class VersionEntry implements BytecodeObjectInterface class VersionEntry implements BytecodeObjectInterface
{ {
@ -39,13 +39,6 @@
*/ */
private $version; private $version;
/**
* The compiler extension used for the package
*
* @var Compiler
*/
private $compiler;
/** /**
* An array of packages that this package depends on * An array of packages that this package depends on
* *
@ -54,9 +47,9 @@
private $dependencies; private $dependencies;
/** /**
* @var ExecutionUnit[] * @var ExecutionPolicy[]
*/ */
public $execution_units; public $execution_policies;
/** /**
* The main execution policy for this version entry if applicable * The main execution policy for this version entry if applicable
@ -65,33 +58,20 @@
*/ */
public $main_execution_policy; public $main_execution_policy;
/**
* The path where the package is located
*
* @var string
*/
public $location;
/** /**
* Public Constructor * Public Constructor
*/ */
public function __construct() public function __construct(string $version)
{ {
$this->version = $version;
$this->dependencies = []; $this->dependencies = [];
$this->execution_units = []; $this->execution_policies = [];
$this->main_execution_policy = null;
} }
/** /**
* Returns installation paths * Returns the version of the package that's installed
* *
* @return InstallationPaths
*/
public function getInstallPaths(): InstallationPaths
{
return new InstallationPaths($this->location);
}
/**
* @return string * @return string
*/ */
public function getVersion(): string public function getVersion(): string
@ -100,71 +80,8 @@
} }
/** /**
* @param string $version * Returns the main execution policy for this version entry if applicable
*/ *
public function setVersion(string $version): void
{
$this->version = $version;
}
/**
* @return Compiler
*/
public function getCompiler(): Compiler
{
return $this->compiler;
}
/**
* @param Compiler $compiler
*/
public function setCompiler(Compiler $compiler): void
{
$this->compiler = $compiler;
}
/**
* @return array|DependencyEntry[]
*/
public function getDependencies(): array
{
return $this->dependencies;
}
/**
* @param array|DependencyEntry[] $dependencies
*/
public function setDependencies(array $dependencies): void
{
$this->dependencies = $dependencies;
}
/**
* @param DependencyEntry $dependency
* @return void
*/
public function addDependency(DependencyEntry $dependency): void
{
$this->dependencies[] = $dependency;
}
/**
* @return array|ExecutionUnit[]
*/
public function getExecutionUnits(): array
{
return $this->execution_units;
}
/**
* @param array|ExecutionUnit[] $execution_units
*/
public function setExecutionUnits(array $execution_units): void
{
$this->execution_units = $execution_units;
}
/**
* @return string|null * @return string|null
*/ */
public function getMainExecutionPolicy(): ?string public function getMainExecutionPolicy(): ?string
@ -173,27 +90,115 @@
} }
/** /**
* @param string|null $main_execution_policy * Sets the main execution policy for this version entry if applicable
*
* @param string|null $policy
* @return void
*/ */
public function setMainExecutionPolicy(?string $main_execution_policy): void public function setMainExecutionPolicy(?string $policy): void
{ {
$this->main_execution_policy = $main_execution_policy; $this->main_execution_policy = $policy;
} }
/** /**
* Returns an array of packages that this package depends on
*
* @return DependencyEntry[]
*/
public function getDependencies(): array
{
return $this->dependencies;
}
/**
* Returns a dependency by name if it exists
*
* @param string $name
* @return DependencyEntry|null
*/
public function getDependency(string $name): ?DependencyEntry
{
foreach($this->dependencies as $dependency)
{
if($dependency->getPackageName() === $name)
{
return $dependency;
}
}
return null;
}
/**
* Adds a dependency to the version entry
*
* @param DependencyEntry $dependency
* @return void
*/
public function addDependency(DependencyEntry $dependency): void
{
if($this->getDependency($dependency->getPackageName()) !== null)
{
return;
}
$this->dependencies[] = $dependency;
}
/**
* Returns an array of execution policies for this version entry
*
* @return ExecutionPolicy[]
*/
public function getExecutionPolicies(): array
{
return $this->execution_policies;
}
/**
* Returns the main execution policy for this version entry if it exists
*
* @param string $name
* @return ExecutionPolicy|null
*/
public function getExecutionPolicy(string $name): ?ExecutionPolicy
{
foreach($this->execution_policies as $executionPolicy)
{
if($executionPolicy->getName() === $name)
{
return $executionPolicy;
}
}
return null;
}
/**
* Adds an execution policy to the version entry
*
* @param ExecutionPolicy $executionPolicy
* @return void
*/
public function addExecutionPolicy(ExecutionPolicy $executionPolicy): void
{
if($this->getExecutionPolicy($executionPolicy->getName()) !== null)
{
return;
}
$this->execution_policies[] = $executionPolicy;
}
/**
* Returns the path where the package is installed
*
* @param string $package_name
* @return string * @return string
*/ */
public function getLocation(): string public function getPath(string $package_name): string
{ {
return $this->location; return PathFinder::getPackagesPath() . DIRECTORY_SEPARATOR . sprintf('%s=%s', $package_name, $this->getVersion());
}
/**
* @param string $location
*/
public function setLocation(string $location): void
{
$this->location = $location;
} }
/** /**
@ -210,19 +215,17 @@
$dependencies[] = $dependency->toArray($bytecode); $dependencies[] = $dependency->toArray($bytecode);
} }
$execution_units = []; $execution_policies = [];
foreach($this->execution_units as $executionUnit) foreach($this->execution_policies as $policy)
{ {
$execution_units[] = $executionUnit->toArray($bytecode); $execution_policies[] = $policy->toArray($bytecode);
} }
return [ return [
($bytecode ? Functions::cbc('version') : 'version') => $this->version, ($bytecode ? Functions::cbc('version') : 'version') => $this->version,
($bytecode ? Functions::cbc('compiler') : 'compiler') => $this->compiler->toArray(),
($bytecode ? Functions::cbc('dependencies') : 'dependencies') => $dependencies, ($bytecode ? Functions::cbc('dependencies') : 'dependencies') => $dependencies,
($bytecode ? Functions::cbc('execution_units') : 'execution_units') => $execution_units, ($bytecode ? Functions::cbc('execution_policies') : 'execution_policies') => $execution_policies,
($bytecode ? Functions::cbc('main_execution_policy') : 'main_execution_policy') => $this->main_execution_policy, ($bytecode ? Functions::cbc('main_execution_policy') : 'main_execution_policy') => $this->main_execution_policy,
($bytecode ? Functions::cbc('location') : 'location') => $this->location,
]; ];
} }
@ -234,11 +237,15 @@
*/ */
public static function fromArray(array $data): VersionEntry public static function fromArray(array $data): VersionEntry
{ {
$object = new self(); $version = Functions::array_bc($data, 'version');
$object->version = Functions::array_bc($data, 'version');
$object->compiler = Compiler::fromArray(Functions::array_bc($data, 'compiler')); if($version === null)
{
throw new ConfigurationException('VersionEntry is missing version');
}
$object = new self($version);
$object->main_execution_policy = Functions::array_bc($data, 'main_execution_policy'); $object->main_execution_policy = Functions::array_bc($data, 'main_execution_policy');
$object->location = Functions::array_bc($data, 'location');
$dependencies = Functions::array_bc($data, 'dependencies'); $dependencies = Functions::array_bc($data, 'dependencies');
if($dependencies !== null) if($dependencies !== null)
@ -249,12 +256,12 @@
} }
} }
$execution_units = Functions::array_bc($data, 'execution_units'); $execution_policies = Functions::array_bc($data, 'execution_policies');
if($execution_units !== null) if($execution_policies !== null)
{ {
foreach($execution_units as $_datum) foreach($execution_policies as $_datum)
{ {
$object->execution_units[] = ExecutionUnit::fromArray($_datum); $object->execution_policies[] = ExecutionPolicy::fromArray($_datum);
} }
} }

View file

@ -436,7 +436,6 @@
public static function fromArray(array $data): BuildConfiguration public static function fromArray(array $data): BuildConfiguration
{ {
$name = Functions::array_bc($data, 'name'); $name = Functions::array_bc($data, 'name');
$build_type = Functions::array_bc($data, 'build_type');
$output_path = Functions::array_bc($data, 'output_path'); $output_path = Functions::array_bc($data, 'output_path');
if($name === null) if($name === null)
@ -451,6 +450,7 @@
$object = new BuildConfiguration($name, $output_path); $object = new BuildConfiguration($name, $output_path);
$object->build_type = Functions::array_bc($data, 'build_type') ?? BuildOutputType::NCC_PACKAGE;
$object->options = Functions::array_bc($data, 'options') ?? []; $object->options = Functions::array_bc($data, 'options') ?? [];
$object->define_constants = Functions::array_bc($data, 'define_constants') ?? []; $object->define_constants = Functions::array_bc($data, 'define_constants') ?? [];
$object->exclude_files = Functions::array_bc($data, 'exclude_files') ?? []; $object->exclude_files = Functions::array_bc($data, 'exclude_files') ?? [];

View file

@ -33,7 +33,7 @@
use ncc\Objects\Vault\Password\AccessToken; use ncc\Objects\Vault\Password\AccessToken;
use ncc\Objects\Vault\Password\UsernamePassword; use ncc\Objects\Vault\Password\UsernamePassword;
use ncc\Utilities\Functions; use ncc\Utilities\Functions;
use ncc\ZiProto\ZiProto; use ncc\Extensions\ZiProto\ZiProto;
use RuntimeException; use RuntimeException;
class Entry implements BytecodeObjectInterface class Entry implements BytecodeObjectInterface

View file

@ -1,242 +0,0 @@
<?php
/*
* Copyright (c) Nosial 2022-2023, all rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, including without
* limitation the rights 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:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
/** @noinspection PhpMissingFieldTypeInspection */
namespace ncc;
use Exception;
use ncc\Enums\CompilerExtensions;
use ncc\Enums\Versions;
use ncc\Classes\PhpExtension\PhpRuntime;
use ncc\Exceptions\ConfigurationException;
use ncc\Exceptions\ImportException;
use ncc\Exceptions\IntegrityException;
use ncc\Exceptions\IOException;
use ncc\Exceptions\PackageException;
use ncc\Managers\PackageManager;
use ncc\Objects\PackageLock\VersionEntry;
use ncc\Objects\ProjectConfiguration\Dependency;
use ncc\Runtime\Constants;
class Runtime
{
/**
* @var PackageManager
*/
private static $package_manager;
/**
* @var array
*/
private static $imported_packages;
/**
* Determines if the package is already imported
*
* @param string $package
* @param string $version
* @return bool
* @throws IOException
*/
private static function isImported(string $package, string $version=Versions::LATEST): bool
{
if($version === Versions::LATEST)
{
$version = self::getPackageManager()->getPackage($package)->getLatestVersion();
}
$entry = "$package=$version";
return isset(self::$imported_packages[$entry]);
}
/**
* Adds a package to the imported packages list
*
* @param string $package
* @param string $version
* @return void
*/
private static function addImport(string $package, string $version): void
{
$entry = "$package=$version";
self::$imported_packages[$entry] = true;
}
/**
* @param string $package
* @param string $version
* @param array $options
* @return void
* @throws IOException
* @throws ImportException
*/
public static function import(string $package, string $version=Versions::LATEST, array $options=[]): void
{
try
{
$package_entry = self::getPackageManager()->getPackage($package);
}
catch (IOException $e)
{
throw new ImportException(sprintf('Failed to import package "%s" due to a package lock exception: %s', $package, $e->getMessage()), $e);
}
if($package_entry === null)
{
throw new ImportException(sprintf("Package '%s' not found", $package));
}
if($version === Versions::LATEST)
{
$version = $package_entry->getLatestVersion();
}
try
{
/** @var VersionEntry $version_entry */
$version_entry = $package_entry->getVersion($version);
if($version_entry === null)
{
throw new ImportException(sprintf('Version %s of %s is not installed', $version, $package));
}
}
catch (IOException $e)
{
throw new ImportException(sprintf('Version %s of %s is not installed', $version, $package), $e);
}
try
{
if (self::isImported($package, $version))
{
return;
}
}
catch (IOException $e)
{
throw new ImportException(sprintf('Failed to check if package %s is imported', $package), $e);
}
if(count($version_entry->getDependencies()) > 0)
{
// Import all dependencies first
/** @var Dependency $dependency */
foreach($version_entry->getDependencies() as $dependency)
{
self::import($dependency->getPackageName(), $dependency->getVersion(), $options);
}
}
try
{
switch($version_entry->getCompiler()->getExtension())
{
case CompilerExtensions::PHP:
PhpRuntime::import($version_entry, $options);
break;
default:
throw new ImportException(sprintf('Compiler extension %s is not supported in this runtime', $version_entry->getCompiler()->getExtension()));
}
}
catch(Exception $e)
{
throw new ImportException(sprintf('Failed to import package %s', $package), $e);
}
self::addImport($package, $version);
}
/**
* Returns the data path of the package
*
* @param string $package
* @return string
* @throws ConfigurationException
* @throws IOException
* @throws PackageException
*/
public static function getDataPath(string $package): string
{
$package = self::getPackageManager()->getPackage($package);
if($package === null)
{
throw new PackageException('Package not found (null entry error, possible bug)');
}
return $package->getDataPath();
}
/**
* @return PackageManager
*/
private static function getPackageManager(): PackageManager
{
if(self::$package_manager === null)
{
self::$package_manager = new PackageManager();
}
return self::$package_manager;
}
/**
* Returns an array of all the packages that is currently imported
*
* @return array
*/
public static function getImportedPackages(): array
{
return array_keys(self::$imported_packages);
}
/**
* Returns a registered constant
*
* @param string $package
* @param string $name
* @return string|null
*/
public static function getConstant(string $package, string $name): ?string
{
return Constants::get($package, $name);
}
/**
* Registers a new constant
*
* @param string $package
* @param string $name
* @param string $value
* @return void
* @throws IntegrityException
*/
public static function setConstant(string $package, string $name, string $value): void
{
Constants::register($package, $name, $value);
}
}

View file

@ -1,247 +0,0 @@
<?php
/**
* Copyright (c) 2009-2019 Arne Blankerts <arne@blankerts.de>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of Arne Blankerts nor the names of contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT * NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER ORCONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @package Autoload
* @author Arne Blankerts <arne@blankerts.de>
* @copyright Arne Blankerts <arne@blankerts.de>, All rights reserved.
* @license BSD License
*
*/
namespace ncc\ThirdParty\theseer\Autoload {
class Application {
private $logger;
private $factory;
private $config;
public function __construct(Logger $logger, Config $config, Factory $factory) {
$this->logger = $logger;
$this->config = $config;
$this->factory = $factory;
}
public function run() {
$result = $this->runCollector();
if (!$result->hasUnits()) {
throw new ApplicationException('No units were found - process aborted.', ApplicationException::NoUnitsFound);
}
if ($result->hasDuplicates()) {
return $this->showDuplicatesError($result->getDuplicates());
}
if ($this->config->isCacheEnabled()) {
$this->factory->getCache()->persist($this->config->getCacheFile());
}
$template = @file_get_contents($this->config->getTemplate());
if ($template === false) {
throw new ApplicationException("Failed to read the template file.");
}
$builder = $this->factory->getRenderer($result);
$code = $builder->render($template);
if ($this->config->isLintMode()) {
return $this->runLint($code);
}
return $this->runSaver($code);
}
/**
* @return CollectorResult
*/
private function runCollector() {
if ($this->config->isFollowSymlinks()) {
$this->logger->log('Following symbolic links is enabled.' . "\n\n");
}
$collector = $this->factory->getCollector();
foreach ($this->config->getDirectories() as $directory) {
if (is_dir($directory)) {
$this->logger->log('Scanning directory ' . $directory . "\n");
$scanner = $this->factory->getScanner()->getIterator($directory);
$collector->processDirectory($scanner);
// this unset is needed to "fix" a segfault on shutdown in some PHP Versions
unset($scanner);
} else {
$file = new \SplFileInfo($directory);
$filter = $this->factory->getFilter(new \ArrayIterator(array($file)));
foreach($filter as $file) {
$this->logger->log('Scanning file ' . $file . "\n");
$collector->processFile($file);
}
}
}
return $collector->getResult();
}
private function runSaver($code) {
$output = $this->config->getOutputFile();
if (!$this->config->isPharMode()) {
if ($output === 'STDOUT') {
$this->logger->log("\n");
echo $code;
$this->logger->log("\n\n");
return CLI::RC_OK;
}
// @codingStandardsIgnoreStart
$written = @file_put_contents($output, $code);
// @codingStandardsIgnoreEnd
if ($written != strlen($code)) {
$this->logger->log("Writing to file '$output' failed.", STDERR);
return CLI::RC_EXEC_ERROR;
}
$this->logger->log("\nAutoload file {$output} generated.\n\n");
return CLI::RC_OK;
}
if (strpos($code, '__HALT_COMPILER();') === FALSE) {
$this->logger->log(
"Warning: Template used in phar mode did not contain required __HALT_COMPILER() call\n" .
"which has been added automatically. The used stub code may not work as intended.\n\n", STDERR);
$code .= $this->config->getLinebreak() . '__HALT_COMPILER();';
}
$pharBuilder = $this->factory->getPharBuilder();
if ($keyfile = $this->config->getPharKey()) {
$pharBuilder->setSignatureKey($this->loadPharSignatureKey($keyfile));
}
if ($aliasName = $this->config->getPharAliasName()) {
$pharBuilder->setAliasName($aliasName);
}
if ($this->config->hasPharHashAlgorithm()) {
$pharBuilder->setSignatureType($this->config->getPharHashAlgorithm());
}
$pharBuilder->build($output, $code);
$this->logger->log("\nphar archive '{$output}' generated.\n\n");
return CLI::RC_OK;
}
private function loadPharSignatureKey($keyfile) {
if (!extension_loaded('openssl')) {
throw new ApplicationException('Extension for OpenSSL not loaded - cannot sign phar archive - process aborted.',
ApplicationException::OpenSSLError);
}
$keydata = file_get_contents($keyfile);
if (strpos($keydata, 'ENCRYPTED') !== FALSE) {
$this->logger->log("Passphrase for key '$keyfile': ");
$g = shell_exec('stty -g');
shell_exec('stty -echo');
$passphrase = trim(fgets(STDIN));
$this->logger->log("\n");
shell_exec('stty ' . $g);
$private = openssl_pkey_get_private($keydata, $passphrase);
} else {
$private = openssl_pkey_get_private($keydata);
}
if (!$private) {
throw new ApplicationException("Opening private key '$keyfile' failed - process aborted.\n\n", ApplicationException::OpenSSLError);
}
return $private;
}
/**
* Execute a lint check on generated code
*
* @param string $code Generated code to lint
*
* @return boolean
*/
protected function runLint($code) {
$dsp = array(
0 => array('pipe', 'r'),
1 => array('pipe', 'w'),
2 => array('pipe', 'w')
);
$binary = $this->config->getPhp();
$process = proc_open($binary . ' -l', $dsp, $pipes);
if (!is_resource($process)) {
$this->logger->log("Opening php binary for linting failed.\n", STDERR);
return 1;
}
fwrite($pipes[0], $code);
fclose($pipes[0]);
fclose($pipes[1]);
$stderr = stream_get_contents($pipes[2]);
fclose($pipes[2]);
$rc = proc_close($process);
if ($rc == 255) {
$this->logger->log("Syntax errors during lint:\n" .
str_replace('in - on line', 'in generated code on line', $stderr) .
"\n", STDERR);
return CLI::RC_LINT_ERROR;
}
$this->logger->log("Lint check of geneated code okay\n\n");
return CLI::RC_OK;
}
/**
* @param array $duplicates
*
* @return int
*/
private function showDuplicatesError(array $duplicates) {
$this->logger->log(
sprintf("\nMultiple declarations of trait(s), interface(s) or class(es). Could not generate autoload map.\n"),
STDERR
);
foreach($duplicates as $unit => $files) {
$this->logger->log(
sprintf("\nUnit '%s' defined in:\n", $unit),
STDERR
);
/** @var array $files */
foreach($files as $file) {
$this->logger->log(
sprintf(" - %s\n", $file),
STDERR
);
}
}
return CLI::RC_DUPLICATES_ERROR;
}
}
class ApplicationException extends \Exception {
const NoUnitsFound = 1;
const OpenSSLError = 2;
}
}

View file

@ -1,297 +0,0 @@
<?php
/**
* Copyright (c) 2009-2019 Arne Blankerts <arne@blankerts.de>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of Arne Blankerts nor the names of contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT * NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER ORCONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @package Autoload
* @author Arne Blankerts <arne@blankerts.de>
* @copyright Arne Blankerts <arne@blankerts.de>, All rights reserved.
* @license BSD License
*/
namespace ncc\ThirdParty\theseer\Autoload {
/**
* Builds spl based autoload code for inclusion into projects
*
* @author Arne Blankerts <arne@blankerts.de>
* @copyright Arne Blankerts <arne@blankerts.de>, All rights reserved.
*/
class AutoloadRenderer {
/**
* Associative array of classes (key) and the files (value) they are in
*
* @var array
*/
protected $classes;
/**
* An optional base dir to strip for the realpath of the filename
*
* @var string
*/
protected $baseDir = '';
/**
* Indenting char(s)
*
* @var string
*/
protected $indent = ' ';
/**
* Char(s) used as linebreak
*
* @var string
*/
protected $linebreak = "\n";
/**
* Timestamp of production start
*
* @var integer
*/
protected $timestamp;
/**
* Format string supplied to date() for use with ___CREATED___
*
* @var string
*/
protected $dateformat = 'r';
/**
* Variables for templates
*
* @var array
*/
protected $variables = array();
/**
* Flag to toggle PHP 5.2 compat mode
*
* @var boolean
*/
protected $compat = false;
/**
* Flag to pass on to spl_autoload_register to prepend
*
* @var bool
*/
private $usePrepend = false;
/**
* Flag to pass on to spl_autoload_register to optionally throw exceptions on registration error
*
* @var bool
*/
private $throwExceptions = false;
/**
* Constructor of AutoloadRenderer class
*
* @param array $classlist Array of classes
*
*/
public function __construct(array $classlist) {
$this->classes = $classlist;
ksort($this->classes);
}
/**
* Toggle PHP 5.2 compat mode
*
* @param boolean $mode Mode to set compat to
*/
public function setCompat($mode) {
$this->compat = $mode;
}
public function enableExceptions() {
$this->throwExceptions = true;
}
public function prependAutoloader() {
$this->usePrepend = true;
}
/**
* Setter for the Basedir
*
* @param string $dir Path to strip from beginning of filenames
*
* @return void
*/
public function setBaseDir($dir) {
$this->baseDir = $dir;
}
/**
* Overwrite default or previously set indenting option
*
* @param string $indent Char(s) to use for indenting
*
* @return void
*/
public function setIndent($indent) {
$this->indent = $indent;
}
/**
* Overwrite default or previously set linebreak chars
*
* @param string $lbs Code to set linebreak
*
* @return void
*/
public function setLineBreak($lbs) {
$this->linebreak = $lbs;
}
/**
* Accessor for current linebreak setting
*
* @return string
*/
public function getLineBreak() {
return $this->linebreak;
}
/**
* Setter to use allow usage of fixed date/time for ___CREATED___
*
* @param integer $time unix timestamp
*
* @throws AutoloadBuilderException
*/
public function setTimestamp($time) {
if (!is_int($time) && null !== $time) {
throw new AutoloadBuilderException("'$time' is not a unix timestamp", AutoloadBuilderException::InvalidTimestamp);
}
$this->timestamp = $time;
}
/**
* Setter to adjust the date/time format output of ___CREATED___
*
* @param string $frmt Date/Time format string
*/
public function setDateTimeFormat($frmt) {
$this->dateformat = $frmt;
}
/**
* Set a variable for use with template code
*
* @param string $name Key name (use as ___key___ in template)
* @param string $value Value to use
*/
public function setVariable($name, $value) {
$this->variables['___'.$name.'___'] = $value;
}
/**
* Resolve relative location of file path to basedir if one is set and fix potential
* broken windows pathnames when run on windows.
*
* @param string $fname
*
* @return string
*/
protected function resolvePath($fname) {
if (empty($this->baseDir)) {
return str_replace('\\', '/', $fname);
}
$basedir = explode(DIRECTORY_SEPARATOR, $this->baseDir);
$filedir = explode(DIRECTORY_SEPARATOR, dirname(realpath($fname)));
$pos = 0;
$max = count($basedir);
while (isset($filedir[$pos]) && $filedir[$pos] == $basedir[$pos]) {
$pos++;
if ($pos == $max) {
break;
}
}
if ($pos == 0) {
return str_replace('\\', '/', $fname);
}
$rel = join('/', array_slice($filedir, $pos));
if (!empty($rel)) {
$rel .= '/';
}
if ($pos<count($basedir)) {
$rel = str_repeat('../', count($basedir)-$pos) . $rel;
}
return '/' . $rel . basename($fname);
}
/**
* Render autoload code into a string
*
* @param string $template
*
* @return string
*/
public function render($template) {
$entries = array();
foreach($this->classes as $class => $file) {
$fname = $this->resolvePath($file);
$entries[] = "'". addslashes($class). "' => '$fname'";
}
$baseDir = '';
if ($this->baseDir) {
$baseDir = $this->compat ? 'dirname(__FILE__) . ' : '__DIR__ . ';
}
$replace = array_merge($this->variables, array(
'___CREATED___' => date( $this->dateformat, $this->timestamp ? $this->timestamp : time()),
'___CLASSLIST___' => join( ',' . $this->linebreak . $this->indent, $entries),
'___BASEDIR___' => $baseDir,
'___AUTOLOAD___' => 'autoload' . md5(serialize($entries)),
'___EXCEPTION___' => $this->throwExceptions ? 'true' : 'false',
'___PREPEND___' => $this->usePrepend ? 'true' : 'false'
));
return str_replace(array_keys($replace), array_values($replace), $template);
}
}
class AutoloadBuilderException extends \Exception {
const TemplateNotFound = 1;
const InvalidTimestamp = 2;
}
}

View file

@ -1,607 +0,0 @@
<?php
/**
* Copyright (c) 2009-2019 Arne Blankerts <arne@blankerts.de>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of Arne Blankerts nor the names of contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT * NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER ORCONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @package Autoload
* @author Arne Blankerts <arne@blankerts.de>
* @copyright Arne Blankerts <arne@blankerts.de>, All rights reserved.
* @license BSD License
*/
namespace ncc\ThirdParty\theseer\Autoload {
/**
* CLI interface to AutoloadRenderer / StaticRenderer
*
* @author Arne Blankerts <arne@blankerts.de>
* @copyright Arne Blankerts <arne@blankerts.de>, All rights reserved.
*/
class CLI {
const RC_OK = 0;
const RC_EXEC_ERROR = 1;
const RC_PARAM_ERROR = 3;
const RC_LINT_ERROR = 4;
const RC_DUPLICATES_ERROR = 5;
private $pharOption;
private $staticOption;
private $helpOption;
private $versionOption;
private $onceOption;
/**
* @var Factory
*/
private $factory;
public function __construct(Factory $factory) {
$this->factory = $factory;
}
/**
* Main executor method
*
* @return void
*/
public function run() {
try {
$this->preBootstrap();
$input = $this->setupInput();
$input->process();
if ($input->getOption('help')->value === TRUE) {
$this->showVersion();
$this->showUsage();
exit(CLI::RC_OK);
}
if ($input->getOption('version')->value === TRUE ) {
$this->showVersion();
exit(CLI::RC_OK);
}
$config = $this->configure($input);
$this->factory->setConfig($config);
if (!$config->isQuietMode()) {
$this->showVersion();
}
$rc = $this->factory->getApplication()->run();
exit($rc);
} catch (CLIEnvironmentException $e) {
$this->showVersion();
fwrite(STDERR, 'Sorry, but your PHP environment is currently not able to run phpab due to');
fwrite(STDERR, "\nthe following issue(s):\n\n" . $e->getMessage() . "\n\n");
fwrite(STDERR, "Please adjust your PHP configuration and try again.\n\n");
exit(CLI::RC_EXEC_ERROR);
} catch (\ezcConsoleException $e) {
$this->showVersion();
echo $e->getMessage() . "\n\n";
$this->showUsage();
exit(CLI::RC_PARAM_ERROR);
} catch (CollectorException $e) {
switch($e->getCode()) {
case CollectorException::InFileRedeclarationFound:
case CollectorException::RedeclarationFound:
case CollectorException::ParseErrror: {
$message = $e->getMessage();
break;
}
default: {
$message = 'Unexpected error in collector process: ' . $e->getMessage() . "\n\nPlease report this as a bug.\n\n";
}
}
$this->showVersion();
fwrite(STDERR, $message . "\n\n");
exit(CLI::RC_EXEC_ERROR);
} catch (\Exception $e) {
$this->showVersion();
fwrite(STDERR, "\nError while processing request:\n - " . $e->getMessage()."\n");
exit(CLI::RC_EXEC_ERROR);
}
}
/**
* @param \ezcConsoleInput $input
*
* @return \ncc\ThirdParty\theseer\Autoload\Config
*/
private function configure(\ezcConsoleInput $input) {
$config = new Config($input->getArguments());
if ($input->getOption('quiet')->value) {
$config->setQuietMode(TRUE);
}
if ($input->getOption('compat')->value) {
$config->setCompatMode(TRUE);
}
if ($input->getOption('tolerant')->value) {
$config->setTolerantMode(TRUE);
}
if ($output = $input->getOption('output')->value) {
$config->setOutputFile($output);
}
if ($input->getOption('phar')->value) {
$compression = \Phar::NONE;
if ($input->getOption('bzip2')->value === TRUE) {
$compression = \Phar::BZ2;
} else if ($input->getOption('gzip')->value === TRUE) {
$compression = \Phar::GZ;
}
$config->enablePharMode(
$compression,
$input->getOption('all')->value,
$input->getOption('key')->value,
$input->getOption('alias')->value
);
$config->setVariable('PHAR',
$input->getOption('alias')->value ? $input->getOption('alias')->value : basename($output)
);
if ($hashAlgorithm = $input->getOption('hash')->value) {
$config->setPharHashAlgorithm($hashAlgorithm);
}
}
if ($input->getOption('cache')->value) {
$config->setCacheFile($input->getOption('cache')->value);
}
if ($basedir = $input->getOption('basedir')->value) {
$config->setBaseDirectory($basedir);
}
$include = $input->getOption('include')->value;
if (!is_array($include)) {
$include = array($include);
}
$config->setInclude($include);
if ($exclude = $input->getOption('exclude')->value) {
if (!is_array($exclude)) {
$exclude = array($exclude);
}
$config->setExclude($exclude);
}
$whitelist = $input->getOption('whitelist')->value;
if (!is_array($whitelist)) {
$whitelist = array($whitelist);
}
$config->setWhitelist($whitelist);
if ($blacklist = $input->getOption('blacklist')->value) {
if (!is_array($blacklist)) {
$blacklist = array($blacklist);
}
$config->setBlacklist($blacklist);
}
if ($input->getOption('static')->value) {
$config->setStaticMode(TRUE);
}
if ($input->getOption('once')->value) {
$config->setOnceMode(TRUE);
}
if ($input->getOption('warm')->value) {
$config->setWarmMode(TRUE);
}
if ($input->getOption('reset')->value) {
$config->setResetMode(TRUE);
}
if ($input->getOption('follow')->value) {
$config->setFollowSymlinks(TRUE);
}
if ($input->getOption('prepend')->value) {
$config->enablePrepend();
}
if ($input->getOption('no-exception')->value) {
$config->disableExceptions();
}
$indent = $input->getOption('indent')->value;
if ($indent !== FALSE) {
$config->setIndent($indent);
}
if ($template = $input->getOption('template')->value) {
$config->setTemplate($template);
}
if ($linebreak = $input->getOption('linebreak')->value) {
$config->setLinebreak($linebreak);
}
if ($input->getOption('nolower')->value) {
$config->setLowercaseMode(FALSE);
}
if ($variables = $input->getOption('var')->value) {
foreach($variables as $var) {
if (strpos($var, '=')===FALSE) {
throw new \RuntimeException("Variable defintion '$var' is invalid and cannot be processed.");
}
list($name, $value) = explode('=', $var, 2);
$config->setVariable($name, $value);
}
}
if ($input->getOption('paranoid')->value || !$input->getOption('trusting')->value) {
$config->setTrusting(FALSE);
}
return $config;
}
/**
* Helper to output version information
*/
protected function showVersion() {
static $shown = false;
if (!$shown) {
$shown = true;
echo Version::getInfoString() . "\n\n";
}
}
/**
* Helper to output usage information
*/
protected function showUsage() {
print <<<EOF
Usage: phpab [switches] <directory1|file1|/path/to/composer.json> [...<directoryN|fileN>]
-i, --include File pattern to include (default: *.php)
-e, --exclude File pattern to exclude
--blacklist Blacklist classname or namespace (wildcards supported)
--whitelist Whitelist classname or namespace (wildcards supported)
-b, --basedir Basedir for filepaths
-t, --template Path to code template to use
-o, --output Output file for generated code (default: STDOUT)
-p, --phar Create a phar archive (requires -o )
--all Include all files in given directory when creating a phar
--alias Specify explicit internal phar alias filename (default: output filename)
--hash Force given hash algorithm (SHA-1, SHA-256 or SHA-512) (requires -p, conflicts with --key)
--bzip2 Compress phar archive using bzip2 (requires -p) (bzip2 required)
--gzip Compress phar archive using gzip (requires -p) (gzip required)
--key OpenSSL key file to use for signing phar archive (requires -p) (openssl required)
-c, --compat Generate PHP 5.2 compatible code
-s, --static Generate a static require file
-w, --warm Generate a static opcache warming file
--reset Add opcache reset call when generating opcache warming file
-1, --prepend Register as first autoloader (prepend to stack, default: append)
-d, --no-exception Do not throw exception on registration problem (default: throw exception)
-n, --nolower Do not lowercase classnames for case insensitivity
-q, --quiet Quiet mode, do not output any processing errors or information
--cache <file> Enable caching and set filename to use for cache storage
--follow Enables following symbolic links (not compatible with phar mode)
--format Dateformat string for timestamp
--linebreak Linebreak style (CR, CRLF or LF, default: LF)
--indent String used for indenting or number of spaces (default: 16 (compat 12) spaces)
--tolerant Ignore Class Redeclarations in the same file
--once Use require_once instead of require when creating a static require file
--trusting Do not check mimetype of files prior to parsing (default)
--paranoid Do check mimetype of files prior to parsing
--var name=foo Assign value 'foo' to variable 'name' to be used in (custom) templates
--lint Run lint on generated code and exit
--lint-php PHP binary to use for linting (default: /usr/bin/php or c:\php\php.exe)
-h, --help Prints this usage information
-v, --version Prints the version and exits
EOF;
}
/**
* @return \ezcConsoleInput
*/
protected function setupInput() {
$input = new \ezcConsoleInput();
$this->versionOption = $input->registerOption( new \ezcConsoleOption( 'v', 'version' ) );
$this->versionOption->shorthelp = 'Prints the version and exits';
$this->versionOption->isHelpOption = TRUE;
$this->helpOption = $input->registerOption( new \ezcConsoleOption( 'h', 'help' ) );
$this->helpOption->isHelpOption = TRUE;
$this->helpOption->shorthelp = 'Prints this usage information';
$input->registerOption( new \ezcConsoleOption(
'', 'cache', \ezcConsoleInput::TYPE_STRING, NULL, FALSE,
'Enable cache and set cache filename'
));
$this->outputOption = $input->registerOption( new \ezcConsoleOption(
'o', 'output', \ezcConsoleInput::TYPE_STRING, 'STDOUT', FALSE,
'Output file for generated code (default: STDOUT)'
));
$this->pharOption = $input->registerOption( new \ezcConsoleOption(
'p', 'phar', \ezcConsoleInput::TYPE_NONE, NULL, FALSE,
'Build a phar archive of directory contents',
NULL,
array( new \ezcConsoleOptionRule( $input->getOption( 'o' ) ) )
));
$input->registerOption( new \ezcConsoleOption(
'', 'all', \ezcConsoleInput::TYPE_NONE, NULL, FALSE,
'Add all files from src dir to phar',
NULL,
array( new \ezcConsoleOptionRule( $input->getOption( 'p' ) ) )
));
$input->registerOption( new \ezcConsoleOption(
'', 'alias', \ezcConsoleInput::TYPE_STRING, NULL, FALSE,
'Provide explicit internal alias filename for phar',
NULL,
array( new \ezcConsoleOptionRule( $input->getOption( 'p' ) ) )
));
$bzip2 = $input->registerOption( new \ezcConsoleOption(
'', 'bzip2', \ezcConsoleInput::TYPE_NONE, NULL, FALSE,
'Compress files phar with bzip2',
NULL,
array( new \ezcConsoleOptionRule( $input->getOption( 'p' ) ) )
));
$gzip = $input->registerOption( new \ezcConsoleOption(
'', 'gzip', \ezcConsoleInput::TYPE_NONE, NULL, FALSE,
'Compress files phar with gzip',
NULL,
array( new \ezcConsoleOptionRule( $input->getOption( 'p' ) ) ),
array( new \ezcConsoleOptionRule( $bzip2 ) )
));
$bzip2->addExclusion(new \ezcConsoleOptionRule($gzip));
$input->registerOption( new \ezcConsoleOption(
'', 'key', \ezcConsoleInput::TYPE_STRING, NULL, FALSE,
'Keyfile to use for signing phar archive',
NULL,
array( new \ezcConsoleOptionRule( $input->getOption( 'p' ) ) )
));
$this->outputOption = $input->registerOption( new \ezcConsoleOption(
'', 'hash', \ezcConsoleInput::TYPE_STRING, NULL, FALSE,
'Force given hash algorithm (SHA-1, SHA-256 or SHA-512) (requires -p)',
NULL,
array( new \ezcConsoleOptionRule( $input->getOption( 'p' ) ) ),
array( new \ezcConsoleOptionRule( $input->getOption( 'key' ) ) )
));
$input->registerOption( new \ezcConsoleOption(
'i', 'include', \ezcConsoleInput::TYPE_STRING, '*.php', TRUE,
'File pattern to include (default: *.php)'
));
$input->registerOption( new \ezcConsoleOption(
'', 'blacklist', \ezcConsoleInput::TYPE_STRING, NULL, TRUE,
'Name pattern to exclude'
));
$input->registerOption( new \ezcConsoleOption(
'', 'whitelist', \ezcConsoleInput::TYPE_STRING, '*', TRUE,
'Name pattern to include (default: *)'
));
$input->registerOption( new \ezcConsoleOption(
'e', 'exclude', \ezcConsoleInput::TYPE_STRING, NULL, TRUE,
'File pattern to exclude'
));
$input->registerOption( new \ezcConsoleOption(
'b', 'basedir', \ezcConsoleInput::TYPE_STRING, NULL, FALSE,
'Basedir for filepaths'
));
$input->registerOption( new \ezcConsoleOption(
't', 'template', \ezcConsoleInput::TYPE_STRING, NULL, FALSE,
'Path to code template to use'
));
$input->registerOption( new \ezcConsoleOption(
'', 'follow', \ezcConsoleInput::TYPE_NONE, NULL, FALSE,
'Enables following symbolic links',
NULL,
array(),
array( new \ezcConsoleOptionRule($this->pharOption) )
));
$input->registerOption( new \ezcConsoleOption(
'', 'format', \ezcConsoleInput::TYPE_STRING, NULL, FALSE,
'Dateformat string for timestamp'
));
$input->registerOption( new \ezcConsoleOption(
'', 'linebreak', \ezcConsoleInput::TYPE_STRING, NULL, FALSE,
'Linebreak style (CR, CR/LF or LF)'
));
$input->registerOption( new \ezcConsoleOption(
'', 'indent', \ezcConsoleInput::TYPE_STRING, NULL, FALSE,
'String used for indenting (default: 3 spaces)'
));
$this->lintOption = $input->registerOption( new \ezcConsoleOption(
'', 'lint', \ezcConsoleInput::TYPE_NONE, NULL, FALSE,
'Run lint on generated code'
));
$input->registerOption( new \ezcConsoleOption(
'', 'lint-php', \ezcConsoleInput::TYPE_STRING, NULL, FALSE,
'PHP binary path for linting (default: /usr/bin/php or c:\\php\\php.exe)',
NULL,
array( new \ezcConsoleOptionRule( $input->getOption( 'lint' ) ) )
));
$compat = $input->registerOption( new \ezcConsoleOption(
'c', 'compat', \ezcConsoleInput::TYPE_NONE, NULL, FALSE,
'Generate PHP 5.2 compliant code'
));
$this->staticOption = $input->registerOption( new \ezcConsoleOption(
's', 'static', \ezcConsoleInput::TYPE_NONE, NULL, FALSE,
'Build a static require file'
));
$input->registerOption( new \ezcConsoleOption(
'', 'tolerant', \ezcConsoleInput::TYPE_NONE, NULL, FALSE,
'Ignore Class Redeclarations in the same file'
));
$trusting = $input->registerOption( new \ezcConsoleOption(
'', 'trusting', \ezcConsoleInput::TYPE_NONE, TRUE, FALSE,
'Do not check mimetype of files prior to parsing'
));
$paranoid = $input->registerOption( new \ezcConsoleOption(
'', 'paranoid', \ezcConsoleInput::TYPE_NONE, FALSE, FALSE,
'Do check mimetype of files prior to parsing',
NULL,
array(),
array( new \ezcConsoleOptionRule($trusting) )
));
$trusting->addExclusion(new \ezcConsoleOptionRule($paranoid));
$this->onceOption = $input->registerOption( new \ezcConsoleOption(
'', 'once', \ezcConsoleInput::TYPE_NONE, NULL, FALSE,
'Use require_once in static require mode',
NULL,
array( new \ezcConsoleOptionRule( $input->getOption( 's' ) ) )
));
$input->registerOption( new \ezcConsoleOption(
'n', 'nolower', \ezcConsoleInput::TYPE_NONE, NULL, FALSE,
'Do not lowercase classnames for case insensitivity'
));
$input->registerOption( new \ezcConsoleOption(
'q', 'quiet', \ezcConsoleInput::TYPE_NONE, NULL, FALSE,
'Run in quiet mode, no output'
));
$input->registerOption( new \ezcConsoleOption(
'1', 'prepend', \ezcConsoleInput::TYPE_NONE, NULL, FALSE,
'Prepend autoloader to stack',
NULL,
array(),
array( new \ezcConsoleOptionRule( $compat ) )
));
$input->registerOption( new \ezcConsoleOption(
'd', 'no-exception', \ezcConsoleInput::TYPE_NONE, NULL, FALSE,
'Disable exceptions on registration error'
));
$input->registerOption( new \ezcConsoleOption(
'', 'var', \ezcConsoleInput::TYPE_STRING, array(), TRUE,
'Assign variable'
));
$warm = $input->registerOption( new \ezcConsoleOption(
'w', 'warm', \ezcConsoleInput::TYPE_NONE, NULL, FALSE,
'generate opcache warming file',
NULL,
array(),
array(
new \ezcConsoleOptionRule($this->pharOption),
new \ezcConsoleOptionRule($this->staticOption)
)
));
$input->registerOption( new \ezcConsoleOption(
'', 'reset', \ezcConsoleInput::TYPE_NONE, NULL, FALSE,
'add reset call to generated opcache warming file',
NULL,
array(
new \ezcConsoleOptionRule($warm)
)
));
$input->argumentDefinition = new \ezcConsoleArguments();
$input->argumentDefinition[0] = new \ezcConsoleArgument('directory');
$input->argumentDefinition[0]->shorthelp = 'The directory to process.';
$input->argumentDefinition[0]->multiple = TRUE;
return $input;
}
private function preBootstrap() {
$required = array('tokenizer', 'fileinfo');
$missing = array();
foreach($required as $test) {
if (!extension_loaded($test)) {
$missing[] = sprintf('ext/%s not installed/enabled', $test);
}
}
if (count($missing)) {
throw new CLIEnvironmentException(
join("\n", $missing),
CLIEnvironmentException::ExtensionMissing
);
}
if (extension_loaded('xdebug')) {
ini_set('xdebug.scream', 0);
ini_set('xdebug.max_nesting_level', 8192);
ini_set('xdebug.show_exception_trace', 0);
if (function_exists('xdebug_disable')) { // Xdebug v2
xdebug_disable();
}
}
}
}
class CLIEnvironmentException extends \Exception {
const ExtensionMissing = 1;
}
}

View file

@ -1,62 +0,0 @@
<?php
namespace ncc\ThirdParty\theseer\Autoload {
class Cache {
/**
* @var CacheEntry[]
*/
private $loadedEntries = array();
/**
* @var CacheEntry[]
*/
private $usedEntries = array();
public function __construct(array $initialEntries) {
$this->loadedEntries = $initialEntries;
}
/**
* @param SourceFile $file
*
* @return bool
*/
public function hasResult(SourceFile $file) {
$pathname = $file->getPathname();
if (!isset($this->loadedEntries[$pathname])) {
return false;
}
return $this->loadedEntries[$pathname]->getTimestamp() === $file->getMTime();
}
public function getResult(SourceFile $file) {
if (!$this->hasResult($file)) {
throw new CacheException('Entry not found');
}
$pathname = $file->getPathname();
$entry = $this->loadedEntries[$pathname];
$this->usedEntries[$pathname] = $entry;
return $entry->getResult();
}
public function addResult(SourceFile $file, ParseResult $result) {
$this->usedEntries[$file->getPathname()] = new CacheEntry($file->getMTime(), $result);
}
public function persist($fname) {
if (file_exists($fname)) {
unlink($fname);
}
file_put_contents($fname, serialize($this->usedEntries));
}
}
class CacheException extends \Exception {
}
}

View file

@ -1,38 +0,0 @@
<?php
namespace ncc\ThirdParty\theseer\Autoload {
class CacheEntry {
/**
* @var ParseResult
*/
private $result;
/**
* @var int
*/
private $timestamp;
public function __construct($timestamp, ParseResult $result) {
$this->timestamp = $timestamp;
$this->result = $result;
}
/**
* @return ParseResult
*/
public function getResult() {
return $this->result;
}
/**
* @return int
*/
public function getTimestamp() {
return $this->timestamp;
}
}
}

View file

@ -1,41 +0,0 @@
<?php
namespace ncc\ThirdParty\theseer\Autoload;
use ncc\ThirdParty\theseer\Autoload\StaticListRenderer;
class CacheWarmingListRenderer implements StaticListRenderer {
/**
* @var bool
*/
private $addReset;
/**
* @var string
*/
private $indent;
private $linebreak;
/**
* @param boolean $addReset
* @param string $indent
* @param string $getLinebreak
*/
public function __construct($addReset, $indent, $linebreak) {
$this->addReset = $addReset;
$this->indent = $indent;
$this->linebreak = $linebreak;
}
/**
* @return string
*/
public function render(array $list) {
$line = $this->indent . 'opcache_compile_file(___BASEDIR___\'';
$glue = '\');' . $this->linebreak . $line;
$firstLine = $this->addReset ? $this->indent . 'opcache_reset();' . $this->linebreak : '';
return $firstLine . $line . implode($glue, $list) . '\');';
}
}

View file

@ -1,42 +0,0 @@
<?php
namespace ncc\ThirdParty\theseer\Autoload {
use ncc\ThirdParty\theseer\Autoload\ParserInterface;
class CachingParser implements ParserInterface {
/**
* @var ParserInterface
*/
private $parser;
/**
* @var Cache
*/
private $cache;
public function __construct(Cache $cache, ParserInterface $parser) {
$this->cache = $cache;
$this->parser = $parser;
}
/**
* Parse a given file for defintions of classes, traits and interfaces
*
* @param SourceFile $source file to process
*
* @return ParseResult
*/
public function parse(SourceFile $source) {
if ($this->cache->hasResult($source)) {
return $this->cache->getResult($source);
}
$result = $this->parser->parse($source);
$this->cache->addResult($source, $result);
return $result;
}
}
}

View file

@ -1,96 +0,0 @@
<?php
namespace ncc\ThirdParty\theseer\Autoload {
use ncc\ThirdParty\theseer\DirectoryScanner\PHPFilterIterator;
class Collector {
/**
* @var ParserInterface
*/
private $parser;
/**
* @var CollectorResult
*/
private $collectorResult;
/**
* @var bool
*/
private $tolerantMode;
/**
* @var bool
*/
private $trustingMode;
/**
* Collector constructor.
*
* @param ParserInterface $parser
* @param bool $tolerantMode
* @param bool $trustingMode
* @param array $whitelist
* @param array $blacklist
*/
public function __construct(ParserInterface $parser, $tolerantMode = false, $trustingMode = true, Array $whitelist = array('*'), Array $blacklist = array()) {
$this->parser = $parser;
$this->tolerantMode = $tolerantMode;
$this->trustingMode = $trustingMode;
$this->collectorResult = new CollectorResult($whitelist, $blacklist);
}
public function getResult() {
return $this->collectorResult;
}
public function processDirectory(\Iterator $sources) {
$worker = $this->trustingMode ? $sources : new PHPFilterIterator($sources);
foreach($worker as $file) {
$this->processFile($file);
}
}
public function processFile(\SplFileInfo $file) {
if ($this->collectorResult->hasResultFor($file)) {
return;
}
try {
$parseResult = $this->parser->parse(new SourceFile($file->getRealPath()));
if ($parseResult->hasRedeclarations() && !$this->tolerantMode) {
throw new CollectorException(
sprintf(
"Duplicate (potentially conditional) definitions of the following unit(s) found:\n\n\tUnit(s): %s\n\tFile: %s",
join(', ', $parseResult->getRedeclarations()),
$file->getRealPath()
),
CollectorException::InFileRedeclarationFound
);
}
$this->collectorResult->addParseResult($file, $parseResult);
} catch(ParserException $e) {
throw new CollectorException(
sprintf(
"Could not process file '%s' due to parse errors: %s",
$file->getRealPath(),
$e->getMessage()
),
CollectorException::ParseErrror,
$e
);
} catch(CollectorResultException $e) {
throw new CollectorException(
$e->getMessage(),
CollectorException::RedeclarationFound
);
}
}
}
class CollectorException extends \Exception {
const ParseErrror = 1;
const RedeclarationFound = 2;
const InFileRedeclarationFound = 3;
}
}

View file

@ -1,118 +0,0 @@
<?php
namespace ncc\ThirdParty\theseer\Autoload {
class CollectorResult {
/**
* @var array
*/
private $whitelist;
/**
* @var array
*/
private $blacklist;
/**
* @var array
*/
private $units = array();
/**
* @var array
*/
private $dependencies = array();
/**
* @var array
*/
private $seenFiles = array();
/**
* @var array
*/
private $duplicates = array();
public function __construct(array $whitelist, array $blacklist) {
$this->whitelist = $whitelist;
$this->blacklist = $blacklist;
}
public function hasResultFor(\SplFileInfo $file) {
return isset($this->seenFiles[$file->getRealPath()]);
}
public function addParseResult(\SplFileInfo $file, ParseResult $result) {
if (!$result->hasUnits()) {
return;
}
$filename = $file->getRealPath();
$this->seenFiles[$filename] = true;
foreach($result->getUnits() as $unit) {
if (!$this->accept($unit)) {
continue;
}
if (isset($this->units[$unit])) {
if (!isset($this->duplicates[$unit])) {
$this->duplicates[$unit] = array( $this->units[$unit] );
}
$this->duplicates[$unit][] = $filename;
continue;
}
$this->units[$unit] = $filename;
$this->dependencies[$unit] = $result->getDependenciesForUnit($unit);
}
}
public function hasUnits() {
return count($this->units) > 0;
}
public function hasDuplicates() {
return count($this->duplicates) > 0;
}
/**
* @return array
*/
public function getDependencies() {
return $this->dependencies;
}
/**
* @return array
*/
public function getUnits() {
return $this->units;
}
/**
* @param string $unit
*
* @return bool
*/
private function accept($unit) {
foreach($this->blacklist as $entry) {
if (fnmatch($entry, $unit)) {
return false;
}
}
foreach($this->whitelist as $entry) {
if (fnmatch($entry, $unit)) {
return true;
}
}
return false;
}
public function getDuplicates() {
return $this->duplicates;
}
}
class CollectorResultException extends \Exception {
const DuplicateUnitName = 1;
}
}

View file

@ -1,183 +0,0 @@
<?php
namespace ncc\ThirdParty\theseer\Autoload {
use Exception;
use Iterator;
use ReturnTypeWillChange;
use SplFileInfo;
class ComposerIterator implements Iterator {
/**
* @var array
*/
private $directories = array();
private $seen = array();
private $pos = 0;
public function __construct(SplFileInfo $composerFile) {
if (!$composerFile->isFile() || !$composerFile->isReadable()) {
throw new ComposerIteratorException(
sprintf('Composer file "%s" not found or not readable', $composerFile->getPathname()),
ComposerIteratorException::InvalidComposerJsonFile
);
}
$composerDir = dirname($composerFile->getRealPath());
$composerData = json_decode(file_get_contents($composerFile->getRealPath()), true);
if (isset($composerData['require'])) {
foreach($composerData['require'] as $require => $version) {
if ($require === 'php' || strpos($require, 'ext-') === 0) {
continue;
}
$this->processRequire($composerDir, $require);
}
}
if (isset($composerData['autoload'])) {
$this->processAutoload($composerDir, $composerData['autoload']);
}
}
private function processAutoload($baseDir, array $map) {
if (isset($map['classmap'])) {
foreach($map['classmap'] as $dir) {
$this->addDirectory($baseDir . '/' . $dir);
}
}
foreach(array('psr-0', 'psr-4') as $psr) {
if (isset($map[$psr])) {
foreach ($map[$psr] as $node => $dir) {
if ($dir === '') {
$this->addDirectory($baseDir);
continue;
}
if (is_array($dir)) {
foreach($dir as $d) {
$this->addDirectory($baseDir . '/' . $d);
}
continue;
}
$this->addDirectory($baseDir . '/' . $dir);
}
}
}
}
private function processRequire($basedir, $require) {
if (isset($this->seen[$require])) {
return;
}
$this->seen[$require] = true;
$requireDir = $basedir . '/vendor/' . $require;
$jsonFile = $this->findComposerJson($requireDir);
if ($jsonFile === null) {
return;
}
$jsonData = json_decode(file_get_contents($jsonFile), true);
if (isset($jsonData['require'])) {
foreach($jsonData['require'] as $entry => $version) {
if ($entry === 'php' || strpos($entry, 'ext-') === 0 || strpos($entry, 'lib-') === 0) {
continue;
}
$this->processRequire($basedir, $entry);
}
}
if (isset($jsonData['autoload'])) {
$this->processAutoload($requireDir, $jsonData['autoload']);
return;
}
$this->addDirectory($requireDir);
}
private function findComposerJson($dir) {
if (file_exists($dir . '/composer.json')) {
return $dir . '/composer.json';
}
foreach(glob($dir . '/*', GLOB_ONLYDIR) as $subDir) {
$result = $this->findComposerJson($subDir);
if ($result !== NULL) {
return $result;
}
}
}
private function addDirectory($dir) {
$dir = rtrim($dir, '/');
if (!in_array($dir, $this->directories)) {
$this->directories[] = $dir;
}
}
/**
* (PHP 5 &gt;= 5.0.0)<br/>
* Return the current element
*
* @link http://php.net/manual/en/iterator.current.php
* @return mixed Can return any type.
*/
#[ReturnTypeWillChange]
public function current() {
return $this->directories[$this->pos];
}
/**
* (PHP 5 &gt;= 5.0.0)<br/>
* Move forward to next element
*
* @link http://php.net/manual/en/iterator.next.php
* @return void Any returned value is ignored.
*/
#[ReturnTypeWillChange]
public function next() {
$this->pos++;
}
/**
* (PHP 5 &gt;= 5.0.0)<br/>
* Return the key of the current element
*
* @link http://php.net/manual/en/iterator.key.php
* @return mixed scalar on success, or null on failure.
*/
#[ReturnTypeWillChange]
public function key() {
return $this->pos;
}
/**
* (PHP 5 &gt;= 5.0.0)<br/>
* Checks if current position is valid
*
* @link http://php.net/manual/en/iterator.valid.php
* @return boolean The return value will be casted to boolean and then evaluated.
* Returns true on success or false on failure.
*/
#[ReturnTypeWillChange]
public function valid() {
return $this->pos < count($this->directories);
}
/**
* (PHP 5 &gt;= 5.0.0)<br/>
* Rewind the Iterator to the first element
*
* @link http://php.net/manual/en/iterator.rewind.php
* @return void Any returned value is ignored.
*/
#[ReturnTypeWillChange]
public function rewind() {
$this->pos = 0;
}
}
class ComposerIteratorException extends Exception {
const InvalidComposerJsonFile = 1;
}
}

View file

@ -1,435 +0,0 @@
<?php
/**
* Copyright (c) 2009-2019 Arne Blankerts <arne@blankerts.de>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of Arne Blankerts nor the names of contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT * NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER ORCONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @package Autoload
* @author Arne Blankerts <arne@blankerts.de>
* @copyright Arne Blankerts <arne@blankerts.de>, All rights reserved.
* @license BSD License
*
*/
namespace ncc\ThirdParty\theseer\Autoload {
class Config {
private $quietMode = FALSE;
private $directories = array();
private $outputFile = 'STDOUT';
private $pharMode = FALSE;
private $include = array('*.php');
private $exclude = array();
private $whitelist = array('*');
private $blacklist = array();
private $baseDirectory = NULL;
private $template;
private $linebreak = "\n";
private $indent;
private $lint = FALSE;
private $php;
private $compatMode = FALSE;
private $staticMode = FALSE;
private $warmMode = FALSE;
private $tolerant = FALSE;
private $trusting = TRUE;
private $once = FALSE;
private $reset = FALSE;
private $lowercase = TRUE;
private $dateFormat;
private $variable = array();
private $pharCompression = 'NONE';
private $pharKey;
private $pharAll = false;
private $pharAliasName = '';
private $pharHashAlgorithm;
private $followSymlinks = false;
private $cacheFilename;
private $prepend = false;
private $exceptions = true;
public function __construct(Array $directories) {
$this->directories = $directories;
$this->php = (PHP_OS === 'WIN' ? 'C:\php\php.exe' : '/usr/bin/php');
}
public function setBaseDirectory($baseDirectory) {
$this->baseDirectory = $baseDirectory;
}
public function getBaseDirectory() {
if ($this->baseDirectory !== NULL) {
return realpath($this->baseDirectory);
}
if ($this->isPharMode()) {
$comparator = new PathComparator($this->directories);
return $comparator->getCommonBase();
}
if ($this->outputFile != 'STDOUT') {
return realpath(dirname($this->outputFile) ?: '.');
}
$tmp = $this->getDirectories();
return realpath(is_dir($tmp[0]) ? $tmp[0] : (dirname($tmp[0]) ?: '.'));
}
public function setCompatMode($compatMode) {
$this->compatMode = $compatMode;
}
public function isCompatMode() {
return $this->compatMode === true;
}
public function setDateFormat($dateFormat) {
$this->dateFormat = $dateFormat;
}
public function getDateFormat() {
return $this->dateFormat;
}
public function setExclude(Array $exclude) {
$this->exclude = $exclude;
}
public function getExclude() {
return $this->exclude;
}
public function setInclude(Array $include) {
$this->include = $include;
}
public function getInclude() {
return $this->include;
}
/**
* @return array
*/
public function getBlacklist() {
return $this->blacklist;
}
/**
* @param array $blacklist
*/
public function setBlacklist($blacklist) {
$this->blacklist = $blacklist;
}
/**
* @return array
*/
public function getWhitelist() {
return $this->whitelist;
}
/**
* @param array $whitelist
*/
public function setWhitelist($whitelist) {
$this->whitelist = $whitelist;
}
public function setIndent($indent) {
$this->indent = $indent;
}
public function getIndent() {
if ($this->indent !== NULL) {
if (is_numeric($this->indent) && (int)$this->indent == $this->indent) {
return str_repeat(' ', (int)$this->indent);
}
return $this->indent;
}
if ($this->isStaticMode() || $this->isWarmMode()) {
return '';
}
return str_repeat(' ', $this->isCompatMode() ? 12 : 16);
}
public function setLinebreak($linebreak) {
$lbr = array('LF' => "\n", 'CR' => "\r", 'CRLF' => "\r\n" );
if (isset($lbr[$linebreak])) {
$this->linebreak = $lbr[$linebreak];
} else {
$this->linebreak = $linebreak;
}
}
public function getLinebreak() {
return $this->linebreak;
}
public function setLintMode($lint) {
$this->lint = (boolean)$lint;
}
public function isLintMode() {
return $this->lint;
}
public function setLowercaseMode($lowercase) {
$this->lowercase = (boolean)$lowercase;
}
public function isLowercaseMode() {
return $this->lowercase;
}
public function setOnceMode($once) {
$this->once = (boolean)$once;
}
public function isOnceMode() {
return $this->once;
}
public function setOutputFile($outputFile) {
$this->outputFile = $outputFile;
}
public function getOutputFile() {
return $this->outputFile;
}
public function enablePharMode($compression = 'NONE', $all = true, $key = NULL, $alias = NULL) {
$this->pharMode = true;
$this->pharCompression = $compression;
$this->pharAll = (boolean)$all;
$this->pharKey = $key;
$this->pharAliasName = $alias;
}
public function isPharMode() {
return $this->pharMode;
}
public function isPharAllMode() {
return $this->pharAll;
}
public function getPharCompression() {
return $this->pharCompression;
}
public function getPharKey() {
return $this->pharKey;
}
public function getPharAliasName() {
return $this->pharAliasName;
}
public function hasPharHashAlgorithm() {
return $this->pharHashAlgorithm !== null;
}
/**
* @return string
*/
public function getPharHashAlgorithm() {
return $this->pharHashAlgorithm;
}
/**
* @param string $pharHashAlgorithm
*/
public function setPharHashAlgorithm($pharHashAlgorithm) {
if (!in_array($pharHashAlgorithm, array('SHA-512','SHA-256','SHA-1'))) {
throw new \InvalidArgumentException(
sprintf('Algorithm %s not supported', $pharHashAlgorithm)
);
}
$this->pharHashAlgorithm = $pharHashAlgorithm;
}
public function setPhp($php) {
$this->php = $php;
}
public function getPhp() {
return $this->php;
}
public function setQuietMode($quietMode) {
$this->quietMode = (boolean)$quietMode;
}
public function setStaticMode($staticMode) {
$this->staticMode = (boolean)$staticMode;
$this->warmMode = FALSE;
}
public function isStaticMode() {
return $this->staticMode;
}
public function setWarmMode($warmMode) {
$this->warmMode = (boolean)$warmMode;
$this->staticMode = FALSE;
}
public function isWarmMode() {
return $this->warmMode;
}
public function setResetMode($resetMode) {
$this->reset = (boolean)$resetMode;
}
public function isResetMode() {
return $this->reset;
}
public function setTemplate($template) {
$this->template = $template;
}
public function getTemplate() {
$tplType = $this->isLowercaseMode() ? 'ci' : 'cs';
$template = $this->template;
if ($template !== NULL) {
if (!file_exists($template)) {
$alternative = __DIR__.'/templates/'. $tplType .'/'.$template;
if (file_exists($alternative)) {
$template = $alternative;
}
$alternative .= '.php.tpl';
if (file_exists($alternative)) {
$template = $alternative;
}
}
return $template;
}
// determine auto template to use
$tplFile = 'default.php.tpl';
if ($this->isCompatMode()) {
$tplFile = 'php52.php.tpl';
}
if ($this->isPharMode()) {
if ($this->isStaticMode()) {
$tplFile = 'staticphar.php.tpl';
$tplType = '.';
} else {
$tplFile = 'phar.php.tpl';
}
} elseif ($this->isStaticMode() || $this->isWarmMode()) {
$tplFile = 'static.php.tpl';
$tplType = '.';
}
return __DIR__.'/templates/'.$tplType.'/'.$tplFile;
}
public function setTolerantMode($tolerant) {
$this->tolerant = (boolean)$tolerant;
}
public function isTolerantMode() {
return $this->tolerant;
}
public function setTrusting($trusting) {
$this->trusting = (boolean)$trusting;
}
public function setFollowSymlinks($followSymlinks) {
$this->followSymlinks = (boolean)$followSymlinks;
}
public function isFollowSymlinks() {
return $this->followSymlinks;
}
public function isTrustingMode() {
return $this->trusting;
}
public function setVariable($name, $value) {
$this->variable[$name] = $value;
}
public function getVariables() {
return $this->variable;
}
public function isQuietMode() {
return $this->quietMode;
}
public function getDirectories() {
$list = array();
foreach($this->directories as $dir) {
if (is_file($dir) && basename($dir) == 'composer.json') {
foreach(new ComposerIterator(new \SplFileInfo($dir)) as $d) {
$list[] = $d;
}
} else {
foreach(glob($dir) as $match) {
$list[] = $match;
}
}
}
return $list;
}
public function setCacheFile($filename) {
$this->cacheFilename = $filename;
}
public function isCacheEnabled() {
return $this->cacheFilename !== NULL;
}
public function getCacheFile() {
return $this->cacheFilename;
}
public function enablePrepend() {
$this->prepend = true;
}
public function usePrepend() {
return $this->prepend;
}
public function disableExceptions() {
$this->exceptions = false;
}
public function useExceptions() {
return $this->exceptions;
}
}
}

View file

@ -1,100 +0,0 @@
<?php
/**
* Copyright (c) 2009-2019 Arne Blankerts <arne@blankerts.de>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of Arne Blankerts nor the names of contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT * NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER ORCONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @package Autoload
* @author Arne Blankerts <arne@blankerts.de>
* @copyright Arne Blankerts <arne@blankerts.de>, All rights reserved.
* @license BSD License
*/
namespace ncc\ThirdParty\theseer\Autoload {
/**
* Sorting classes by depdendency for static requires
*
* @author Arne Blankerts <arne@blankerts.de>
* @copyright Arne Blankerts <arne@blankerts.de>, All rights reserved.
*/
class ClassDependencySorter {
private $classList;
private $dependencies;
private $level;
private $sorted = array();
public function __construct(Array $classes, Array $dependencies) {
$this->classList = $classes;
$this->dependencies = $dependencies;
}
public function process() {
$this->level = 0;
foreach($this->classList as $class => $file) {
if (!in_array($class, $this->sorted)) {
$this->resolve($class);
}
}
$res = array();
foreach($this->sorted as $class) {
if (!isset($this->classList[$class])) {
continue;
}
$res[$class] = $this->classList[$class];
}
return $res;
}
private function resolve($class) {
$this->level++;
if ($this->level == 50) {
throw new ClassDependencySorterException("Can't resolve more than 50 levels of dependencies", ClassDependencySorterException::TooManyDependencyLevels);
}
if (isset($this->dependencies[$class])) {
foreach($this->dependencies[$class] as $depclass) {
if (!in_array($depclass, $this->sorted)) {
$this->resolve($depclass);
}
}
}
$this->sorted[] = $class;
$this->level--;
}
}
class ClassDependencySorterException extends \Exception {
const TooManyDependencyLevels = 1;
}
}

View file

@ -1,242 +0,0 @@
<?php
/**
* Copyright (c) 2009-2019 Arne Blankerts <arne@blankerts.de>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of Arne Blankerts nor the names of contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT * NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER ORCONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @package Autoload
* @author Arne Blankerts <arne@blankerts.de>
* @copyright Arne Blankerts <arne@blankerts.de>, All rights reserved.
* @license BSD License
*
*/
namespace ncc\ThirdParty\theseer\Autoload {
use ncc\ThirdParty\theseer\DirectoryScanner\DirectoryScanner;
use ncc\ThirdParty\theseer\DirectoryScanner\IncludeExcludeFilterIterator;
class Factory {
/**
* @var Config
*/
private $config;
/**
* @var Cache
*/
private $cache;
/**
* @param \ncc\ThirdParty\theseer\Autoload\Config $config
*/
public function setConfig(Config $config) {
$this->config = $config;
}
/**
* @return CLI
*/
public function getCLI() {
return new CLI($this);
}
/**
* @return Application
*/
public function getApplication() {
return new Application($this->getLogger(), $this->config, $this);
}
public function getLogger() {
return new Logger($this->config->isQuietMode());
}
/**
* @return Parser
*/
public function getParser() {
$parser = new Parser(
$this->config->isLowercaseMode()
);
if (!$this->config->isCacheEnabled()) {
return $parser;
}
return new CachingParser(
$this->getCache(),
$parser
);
}
/**
* @return Cache
*/
public function getCache() {
if (!$this->cache instanceof Cache) {
$fname = $this->config->getCacheFile();
if (file_exists($fname)) {
$data = unserialize(file_get_contents($fname));
} else {
$data = array();
}
$this->cache = new Cache($data);
}
return $this->cache;
}
public function getCollector() {
return new Collector(
$this->getParser(),
$this->config->isTolerantMode(),
$this->config->isTrustingMode(),
$this->config->getWhitelist(),
$this->config->getBlacklist()
);
}
/**
* Get instance of DirectoryScanner with filter options applied
*
* @param bool $filter
* @return DirectoryScanner
*/
public function getScanner($filter = TRUE) {
$scanner = new DirectoryScanner;
if ($filter) {
$scanner->setIncludes($this->config->getInclude());
$scanner->setExcludes($this->config->getExclude());
}
if ($this->config->isFollowSymlinks()) {
$scanner->setFlag(\FilesystemIterator::FOLLOW_SYMLINKS);
}
return $scanner;
}
public function getFilter(\Iterator $files) {
$filter = new IncludeExcludeFilterIterator($files);
$filter->setInclude($this->config->getInclude());
$filter->setExclude($this->config->getExclude());
return $filter;
}
public function getPharBuilder() {
$builder = new PharBuilder(
$this->getScanner(!$this->config->isPharAllMode()),
$this->config->getBaseDirectory()
);
$builder->setCompressionMode($this->config->getPharCompression());
foreach($this->config->getDirectories() as $directory) {
$builder->addDirectory($directory);
}
return $builder;
}
/**
* Helper to get instance of AutoloadRenderer with cli options applied
*
* @param CollectorResult $result
*
* @return \ncc\ThirdParty\theseer\Autoload\AutoloadRenderer|\ncc\ThirdParty\theseer\Autoload\StaticRenderer
* @throws \RuntimeException
*/
public function getRenderer(CollectorResult $result) {
$isStatic = $this->config->isStaticMode();
$isPhar = $this->config->isPharMode();
$isCompat = $this->config->isCompatMode();
$isOnce = $this->config->isOnceMode();
$isWarm = $this->config->isWarmMode();
$isReset = $this->config->isResetMode();
if ($isWarm === TRUE) {
$renderer = new StaticRenderer(
$result->getUnits(),
$this->getCacheWarmingListRenderer($isReset)
);
$renderer->setDependencies($result->getDependencies());
$renderer->setPharMode($isPhar);
} else if ($isStatic === TRUE) {
$renderer = new StaticRenderer(
$result->getUnits(),
$this->getStaticRequireListRenderer($isOnce)
);
$renderer->setDependencies($result->getDependencies());
$renderer->setPharMode($isPhar);
} else {
$renderer = new AutoloadRenderer($result->getUnits());
if ($this->config->usePrepend()) {
$renderer->prependAutoloader();
}
if ($this->config->useExceptions()) {
$renderer->enableExceptions();
}
}
$renderer->setCompat($isCompat);
$basedir = $this->config->getBaseDirectory();
if (!$basedir || !is_dir($basedir)) {
throw new \RuntimeException("Given basedir '{$basedir}' does not exist or is not a directory");
}
$renderer->setBaseDir($basedir);
$format = $this->config->getDateFormat();
if ($format) {
$renderer->setDateTimeFormat($format);
}
$renderer->setIndent($this->config->getIndent());
$renderer->setLineBreak($this->config->getLinebreak());
foreach($this->config->getVariables() as $name => $value) {
$renderer->setVariable($name, $value);
}
return $renderer;
}
private function getStaticRequireListRenderer($useOnce) {
return new StaticRequireListRenderer(
$useOnce,
$this->config->getIndent(),
$this->config->getLinebreak()
);
}
private function getCacheWarmingListRenderer($addReset) {
return new CacheWarmingListRenderer(
$addReset,
$this->config->getIndent(),
$this->config->getLinebreak()
);
}
}
}

View file

@ -1,31 +0,0 @@
Autoload Builder
Copyright (c) 2010-2016 Arne Blankerts <arne@blankerts.de> and Contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of Arne Blankerts nor the names of contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT * NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER ORCONTRIBUTORS
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

View file

@ -1,59 +0,0 @@
<?php
/**
* Copyright (c) 2009-2019 Arne Blankerts <arne@blankerts.de>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of Arne Blankerts nor the names of contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT * NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER ORCONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @package Autoload
* @author Arne Blankerts <arne@blankerts.de>
* @copyright Arne Blankerts <arne@blankerts.de>, All rights reserved.
* @license BSD License
*
*/
namespace ncc\ThirdParty\theseer\Autoload {
class Logger {
private $quiet = FALSE;
/**
* @param bool $quietMode
*/
public function __construct($quietMode = FALSE) {
$this->quiet = $quietMode;
}
public function log($message, $target = STDOUT) {
if ($this->quiet) {
return;
}
fwrite($target, $message);
}
}
}

View file

@ -1,64 +0,0 @@
<?php
namespace ncc\ThirdParty\theseer\Autoload {
class ParseResult {
/**
* @var string[]
*/
private $units = array();
/**
* @var array
*/
private $dependencies = array();
/**
* @var string[]
*/
private $redeclarations = array();
public function __construct(Array $units, Array $dependencies, Array $redeclarations) {
$this->units = $units;
$this->dependencies = $dependencies;
$this->redeclarations = $redeclarations;
}
public function hasUnits() {
return count($this->units) > 0;
}
public function hasRedeclarations() {
return count($this->redeclarations) > 0;
}
/**
*
* @param string $unit
*
* @return array
*/
public function getDependenciesForUnit($unit) {
if (!isset($this->dependencies[$unit])) {
return array();
}
return $this->dependencies[$unit];
}
/**
* @return \string[]
*/
public function getRedeclarations() {
return $this->redeclarations;
}
/**
* @return \string[]
*/
public function getUnits() {
return $this->units;
}
}
}

View file

@ -1,598 +0,0 @@
<?php
/**
* Copyright (c) 2009-2019 Arne Blankerts <arne@blankerts.de>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of Arne Blankerts nor the names of contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT * NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER ORCONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @package Autoload
* @author Arne Blankerts <arne@blankerts.de>
* @copyright Arne Blankerts <arne@blankerts.de>, All rights reserved.
* @license BSD License
*/
namespace ncc\ThirdParty\theseer\Autoload {
// PHP 5.3 compat
define('T_TRAIT_53', 10355);
if (!defined('T_TRAIT')) {
define('T_TRAIT', -1);
}
// PHP 8.0 forward compat
if (!defined('T_NAME_FULLY_QUALIFIED')) {
define('T_NAME_FULLY_QUALIFIED', -1);
define('T_NAME_QUALIFIED', -1);
}
// PHP 8.1 forward compat
if (!defined('T_ENUM')) {
define('T_ENUM', -1);
}
/**
* Namespace aware parser to find and extract defined classes within php source files
*
* @author Arne Blankerts <arne@blankerts.de>
* @copyright Arne Blankerts <arne@blankerts.de>, All rights reserved.
*/
class Parser implements ParserInterface {
private $methodMap = array(
T_TRAIT => 'processClass',
T_TRAIT_53 => 'processClass',
T_CLASS => 'processClass',
T_ENUM => 'processEnum',
//T_CASE => 'processEnumCase',
T_INTERFACE => 'processInterface',
T_NAMESPACE => 'processNamespace',
T_USE => 'processUse',
'}' => 'processBracketClose',
'{' => 'processBracketOpen',
T_CURLY_OPEN => 'processBracketOpen',
T_DOLLAR_OPEN_CURLY_BRACES => 'processBracketOpen'
);
private $typeMap = array(
T_INTERFACE => 'interface',
T_CLASS => 'class',
T_ENUM => 'enum',
T_TRAIT => 'trait',
T_TRAIT_53 => 'trait'
);
private $caseInsensitive;
private $tokenArray = array();
private $inNamespace = '';
private $inUnit = '';
private $nsBracket = 0;
private $classBracket = 0;
private $bracketLevel = 0;
private $aliases = array();
private $found = array();
private $dependencies = array();
private $redeclarations = array();
public function __construct($caseInsensitive = true) {
$this->caseInsensitive = $caseInsensitive;
}
/**
* Parse a given file for defintions of classes, traits and interfaces
*
* @param SourceFile $source file to process
*
* @return ParseResult
*/
public function parse(SourceFile $source) {
$this->found = array();
$this->redeclarations = array();
$this->inNamespace = '';
$this->aliases = array();
$this->bracketLevel = 0;
$this->inUnit = '';
$this->nsBracket = 0;
$this->classBracket = 0;
$this->tokenArray = $source->getTokens();
$tokenCount = count($this->tokenArray);
$tokList = array_keys($this->methodMap);
for($t=0; $t<$tokenCount; $t++) {
$current = (array)$this->tokenArray[$t];
if ($current[0]===T_STRING && $current[1]==='trait' && T_TRAIT===-1) {
// PHP < 5.4 compat fix
$current[0] = T_TRAIT_53;
$this->tokenArray[$t] = $current;
}
if (!in_array($current[0], $tokList)) {
continue;
}
$t = call_user_func(array($this, $this->methodMap[$current[0]]), $t);
}
return new ParseResult($this->found, $this->dependencies, $this->redeclarations);
}
private function processBracketOpen($pos) {
$this->bracketLevel++;
return $pos + 1;
}
private function processBracketClose($pos) {
$this->bracketLevel--;
if ($this->nsBracket !== 0 && $this->bracketLevel < $this->nsBracket) {
$this->inNamespace = '';
$this->nsBracket = 0;
$this->aliases = array();
}
if ($this->bracketLevel <= $this->classBracket) {
$this->classBracket = 0;
$this->inUnit = '';
}
return $pos + 1;
}
private function processClass($pos) {
if (!$this->classTokenNeedsProcessing($pos)) {
return $pos;
}
$list = array('{');
$stack = $this->getTokensTill($pos, $list);
$stackSize = count($stack);
$classname = $this->inNamespace !== '' ? $this->inNamespace . '\\' : '';
$extends = '';
$extendsFound = false;
$implementsFound = false;
$implementsList = array();
$implements = '';
$mode = 'classname';
foreach(array_slice($stack, 1, -1) as $tok) {
switch ($tok[0]) {
case T_COMMENT:
case T_DOC_COMMENT:
case T_WHITESPACE: {
break;
}
case T_NAME_FULLY_QUALIFIED:
case T_NAME_QUALIFIED:
case T_STRING: {
$$mode .= $tok[1];
break;
}
case T_NS_SEPARATOR: {
$$mode .= '\\';
break;
}
case T_EXTENDS: {
$extendsFound = true;
$mode = 'extends';
break;
}
case T_IMPLEMENTS: {
$implementsFound = true;
$mode = 'implements';
break;
}
case ',': {
if ($mode === 'implements') {
$implementsList[] = $this->resolveDependencyName($implements);
$implements = '';
}
break;
}
default: {
throw new ParserException(sprintf(
'Parse error while trying to process class definition (unexpected token "%s" in name).',
\token_name($tok[0])
), ParserException::ParseError
);
}
}
}
if ($implements != '') {
$implementsList[] = $this->resolveDependencyName($implements);
}
if ($implementsFound && count($implementsList)==0) {
throw new ParserException(sprintf(
'Parse error while trying to process class definition (extends or implements).'
), ParserException::ParseError
);
}
$classname = $this->registerUnit($classname, $stack[0][0]);
$this->dependencies[$classname] = $implementsList;
if ($extendsFound) {
$this->dependencies[$classname][] = $this->resolveDependencyName($extends);
}
$this->inUnit = $classname;
$this->classBracket = $this->bracketLevel + 1;
return $pos + $stackSize - 1;
}
private function processEnum($pos) {
$list = array('{');
$stack = $this->getTokensTill($pos, $list);
$stackSize = count($stack);
$enumName = $this->inNamespace !== '' ? $this->inNamespace . '\\' : '';
$implementsFound = false;
$implementsList = array();
$implements = '';
$backType = '';
$mode = 'enumName';
foreach(array_slice($stack, 1, -1) as $tok) {
switch ($tok[0]) {
case T_COMMENT:
case T_DOC_COMMENT:
case T_WHITESPACE: {
break;
}
case T_NAME_FULLY_QUALIFIED:
case T_NAME_QUALIFIED:
case T_STRING: {
$$mode .= $tok[1];
break;
}
case T_NS_SEPARATOR: {
$$mode .= '\\';
break;
}
case T_IMPLEMENTS: {
$implementsFound = true;
$mode = 'implements';
break;
}
case ':': {
$isBacked = true;
$mode = 'backType';
break;
}
case ',': {
if ($mode === 'implements') {
$implementsList[] = $this->resolveDependencyName($implements);
$implements = '';
}
break;
}
default: {
throw new ParserException(sprintf(
'Parse error while trying to process class definition (unexpected token "%s" in name).',
is_int($tok[0]) ? \token_name($tok[0]) : $tok[0]
), ParserException::ParseError
);
}
}
}
if ($implements != '') {
$implementsList[] = $this->resolveDependencyName($implements);
}
if ($implementsFound && count($implementsList)==0) {
throw new ParserException(sprintf(
'Parse error while trying to process enum definition (implements).'
), ParserException::ParseError
);
}
$enumName = $this->registerUnit($enumName, $stack[0][0]);
$this->dependencies[$enumName] = $implementsList;
return $pos + $stackSize - 1;
}
private function processInterface($pos) {
$list = array('{');
$stack = $this->getTokensTill($pos, $list);
$stackSize = count($stack);
$next = $stack[1];
if (is_array($next) && $next[0] === '(') {
// sort of inline use - ignore
return $pos + $stackSize;
}
$name = $this->inNamespace != '' ? $this->inNamespace . '\\' : '';
$extends = '';
$extendsList = array();
$mode = 'name';
foreach(array_slice($stack, 1, -1) as $tok) {
switch ($tok[0]) {
case T_NS_SEPARATOR:
case T_NAME_QUALIFIED:
case T_NAME_FULLY_QUALIFIED:
case T_STRING: {
$$mode .= $tok[1];
break;
}
case T_EXTENDS: {
$mode = 'extends';
break;
}
case ',': {
if ($mode == 'extends') {
$extendsList[] = $this->resolveDependencyName($extends);
$extends = '';
}
}
}
}
$name = $this->registerUnit($name, T_INTERFACE);
if ($extends != '') {
$extendsList[] = $this->resolveDependencyName($extends);
}
$this->dependencies[$name] = $extendsList;
$this->inUnit = $name;
return $pos + $stackSize - 1;
}
private function resolveDependencyName($name) {
if ($name == '') {
throw new ParserException(sprintf(
'Parse error while trying to process class definition (extends or implements).'
), ParserException::ParseError
);
}
if ($name[0] == '\\') {
$name = substr($name, 1);
} else {
$parts = explode('\\', $name, 2);
$search = $this->caseInsensitive ? strtolower($parts[0]) : $parts[0];
$key = array_search($search, $this->aliases);
if (!$key) {
$name = ($this->inNamespace != '' ? $this->inNamespace . '\\' : ''). $name;
} else {
$name = $key;
if (isset($parts[1])) {
$name .= '\\' . $parts[1];
}
}
}
if ($this->caseInsensitive) {
$name = strtolower($name);
}
return $name;
}
private function registerUnit($name, $type) {
if ($name == '' || substr($name, -1) == '\\') {
throw new ParserException(sprintf(
'Parse error while trying to process %s definition.',
$this->typeMap[$type]
), ParserException::ParseError
);
}
if ($this->caseInsensitive) {
$name = strtolower($name);
}
if (in_array($name, $this->found)) {
$this->redeclarations[] = $name;
} else {
$this->found[] = $name;
}
return $name;
}
private function processNamespace($pos) {
$list = array(';', '{');
$stack = $this->getTokensTill($pos, $list);
$stackSize = count($stack);
$newpos = $pos + $stackSize;
if ($stackSize < 3) { // empty namespace defintion == root namespace
$this->inNamespace = '';
$this->aliases = array();
return $newpos - 1;
}
$next = $stack[1];
if (is_array($next) && ($next[0] === T_NS_SEPARATOR || $next[0] === '(')) {
// sort of inline use - ignore
return $newpos;
}
$this->inNamespace = '';
foreach(array_slice($stack, 1, -1) as $tok) {
$this->inNamespace .= $tok[1];
}
$this->aliases = array();
return $pos + $stackSize - 1;
}
private function processUse($pos) {
$list = array(';','(');
$stack = $this->getTokensTill($pos, $list);
$stackSize = count($stack);
$ignore = array(
'(', // closue use
T_CONST, // use const foo\bar;
T_FUNCTION // use function foo\bar;
);
if (in_array($stack[1][0], $ignore)) {
return $pos + $stackSize - 1;
}
if ($this->classBracket > 0) {
$this->parseUseOfTrait($stackSize, $stack);
} else {
$this->parseUseAsImport($stack);
}
return $pos + $stackSize - 1;
}
private function getTokensTill($start, $list) {
$list = (array)$list;
$stack = array();
$skip = array(
T_WHITESPACE,
T_COMMENT,
T_DOC_COMMENT
);
$limit = count($this->tokenArray);
for ($t=$start; $t<$limit; $t++) {
$current = (array)$this->tokenArray[$t];
if (in_array($current[0], $skip)) {
continue;
}
$stack[] = $current;
if (in_array($current[0], $list)) {
break;
}
}
return $stack;
}
/**
* @param $stackSize
* @param $stack
*/
private function parseUseOfTrait($stackSize, $stack) {
$use = '';
for ($t = 0; $t < $stackSize; $t++) {
$current = (array)$stack[$t];
switch ($current[0]) {
case '{': {
// find closing bracket to skip contents
for ($x = $t + 1; $x < $stackSize; $x++) {
$tok = $stack[$x];
if ($tok[0] == '}') {
$t = $x;
break;
}
}
break;
}
case ';':
case ',': {
$this->dependencies[$this->inUnit][] = $this->resolveDependencyName($use);
$use = '';
break;
}
case T_NS_SEPARATOR:
case T_NAME_QUALIFIED:
case T_NAME_FULLY_QUALIFIED:
case T_STRING: {
$use .= $current[1];
break;
}
}
}
}
/**
* @param $stack
*/
private function parseUseAsImport($stack) {
$use = '';
$alias = '';
$mode = 'use';
$group = '';
$ignore = false;
foreach ($stack as $tok) {
$current = $tok;
switch ($current[0]) {
case T_CONST:
case T_FUNCTION: {
$ignore = true;
break;
}
case '{': {
$group = $use;
break;
}
case ';':
case ',': {
if (!$ignore) {
if ($alias == '') {
$nss = strrpos($use, '\\');
if ($nss !== FALSE) {
$alias = substr($use, $nss + 1);
} else {
$alias = $use;
}
}
if ($this->caseInsensitive) {
$alias = strtolower($alias);
}
$this->aliases[$use] = $alias;
}
$alias = '';
$use = $group;
$mode = 'use';
$ignore = false;
break;
}
case T_NS_SEPARATOR:
case T_NAME_QUALIFIED:
case T_NAME_FULLY_QUALIFIED:
case T_STRING: {
$$mode .= $current[1];
break;
}
case T_AS: {
$mode = 'alias';
break;
}
}
}
}
private function classTokenNeedsProcessing($position) {
// PHP 5.5 has classname::class, reusing T_CLASS
if ($this->tokenArray[$position-1][0] == T_DOUBLE_COLON) {
return false;
}
// PHP 7 has anonymous classes: $x = new class { ... }
if ($position > 2 && $this->tokenArray[$position-2][0] === T_NEW) {
return false;
}
if ($this->tokenArray[$position + 1] === '(' || $this->tokenArray[$position + 2] === '(') {
return false;
}
return true;
}
}
class ParserException extends \Exception {
const ParseError = 1;
}
}

View file

@ -1,20 +0,0 @@
<?php
namespace ncc\ThirdParty\theseer\Autoload;
/**
* Namespace aware parser to find and extract defined classes within php source files
*
* @author Arne Blankerts <arne@blankerts.de>
* @copyright Arne Blankerts <arne@blankerts.de>, All rights reserved.
*/
interface ParserInterface {
/**
* Parse a given file for defintions of classes, traits and interfaces
*
* @param SourceFile $source file to process
*
* @return ParseResult
*/
public function parse(SourceFile $source);
}

View file

@ -1,45 +0,0 @@
<?php
namespace ncc\ThirdParty\theseer\Autoload {
class PathComparator {
/**
* @var string[]
*/
private $directories = array();
/**
* PathComparator constructor.
*
* @param array $directories
*/
public function __construct(array $directories) {
foreach($directories as $dir) {
$this->directories[] = realpath($dir).'/';
}
}
public function getCommonBase() {
if (count($this->directories) == 0) {
return '/';
}
$result = $this->directories[0];
foreach($this->directories as $dir) {
$result = substr($dir, 0, $this->commonPrefix($result, $dir));
}
return ($result ?: '/');
}
private function commonPrefix( $s1, $s2 ) {
$l1 = strlen($s1);
$l2 = strlen($s2);
$i=0;
while($i < $l1 && $i < $l2 && $s1[$i] == $s2[$i]) {
$i++;
}
return strrpos(substr($s1, 0, $i), '/');
}
}
}

Some files were not shown because too many files have changed in this diff Show more