Ejemplo n.º 1
0
        static List <Encoding> ResolveEncodingList(Context ctx, PhpValue encoding_list, bool ignoreInvalid = false)
        {
            IEnumerable <string> enc_names;

            var newlist = new List <Encoding>(4);
            var arrlist = encoding_list.AsArray();

            if (arrlist != null)
            {
                enc_names = arrlist.Values.Select(x => x.ToString(ctx));
            }
            else
            {
                var strlist = encoding_list.ToString(ctx);
                enc_names = strlist.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
            }

            foreach (var n in enc_names)
            {
                var enc = GetEncoding(n.Trim());
                if (enc == null)
                {
                    if (ignoreInvalid)
                    {
                        continue;
                    }

                    return(null);
                }

                newlist.Add(enc);
            }

            return(newlist);
        }
Ejemplo n.º 2
0
        public static PhpValue preg_replace_callback(Context ctx, PhpValue pattern, IPhpCallable callback, PhpValue subject, long limit, ref long count)
        {
            count = 0;

            // PHP's behaviour for undocumented limit range
            if (limit < -1)
            {
                limit = 0;
            }

            //
            var pattern_array = pattern.AsArray();

            if (pattern_array == null)
            {
                // string pattern
                return(PregReplaceInternal(ctx, pattern.ToStringOrThrow(ctx), null, callback, subject, (int)limit, ref count));
            }
            else
            {
                // array pattern
            }

            throw new NotImplementedException();
        }
Ejemplo n.º 3
0
        static PhpValue PregReplaceInternal(Context ctx, string pattern, string replacement, IPhpCallable callback, PhpValue subject, int limit, ref long count)
        {
            var regex = new PerlRegex.Regex(pattern);

            // callback
            PerlRegex.MatchEvaluator evaluator = null;
            if (callback != null)
            {
                evaluator = (match) =>
                {
                    var matches_arr = new PhpArray(0);
                    GroupsToPhpArray(match.PcreGroups, false, matches_arr);

                    return(callback
                           .Invoke(ctx, (PhpValue)matches_arr)
                           .ToStringOrThrow(ctx));
                };
            }

            // TODO: subject as a binary string would be corrupted after Replace - https://github.com/peachpiecompiler/peachpie/issues/178

            //
            var subject_array = subject.AsArray();

            if (subject_array == null)
            {
                return(PhpValue.Create(
                           evaluator == null
                        ? regex.Replace(subject.ToStringOrThrow(ctx), replacement, limit, ref count)
                        : regex.Replace(subject.ToStringOrThrow(ctx), evaluator, limit, ref count)));
            }
            else
            {
                var arr = new PhpArray(subject_array.Count);

                var enumerator = subject_array.GetFastEnumerator();
                while (enumerator.MoveNext())
                {
                    var newvalue = evaluator == null
                        ? regex.Replace(enumerator.CurrentValue.ToStringOrThrow(ctx), replacement, limit, ref count)
                        : regex.Replace(enumerator.CurrentValue.ToStringOrThrow(ctx), evaluator, limit, ref count);

                    // TODO: trick on how to quickly update values od enumerated array without hashing:
                    // enumerator.CurrentValue = PhpValue.Create(newvalue);

                    arr[enumerator.CurrentKey] = newvalue;
                }

                return(PhpValue.Create(arr));
            }
        }
Ejemplo n.º 4
0
        static PhpValue PregReplaceInternal(Context ctx, string pattern, string replacement, IPhpCallable callback, PhpValue subject, int limit, ref long count)
        {
            var regex = new PerlRegex.Regex(pattern);

            // TODO: count

            // callback
            PerlRegex.MatchEvaluator evaluator = null;
            if (callback != null)
            {
                evaluator = (match) =>
                {
                    var matches_arr = new PhpArray(0);
                    foreach (PerlRegex.Group g in match.Groups)
                    {
                        matches_arr.Add((PhpValue)g.Value);
                    }

                    return(callback
                           .Invoke(ctx, (PhpValue)matches_arr)
                           .ToStringOrThrow(ctx));
                };
            }

            //
            var subject_array = subject.AsArray();

            if (subject_array == null)
            {
                return(PhpValue.Create(
                           evaluator == null
                        ? regex.Replace(subject.ToStringOrThrow(ctx), replacement, limit)
                        : regex.Replace(subject.ToStringOrThrow(ctx), evaluator, limit)));
            }
            else
            {
                var arr        = new PhpArray(subject_array, false);
                var enumerator = arr.GetFastEnumerator();
                while (enumerator.MoveNext())
                {
                    var newvalue = evaluator == null
                        ? regex.Replace(enumerator.CurrentValue.ToStringOrThrow(ctx), replacement, limit)
                        : regex.Replace(enumerator.CurrentValue.ToStringOrThrow(ctx), evaluator, limit);

                    enumerator.CurrentValue = PhpValue.Create(newvalue);
                }

                return(PhpValue.Create(arr));
            }
        }
Ejemplo n.º 5
0
        public virtual void __construct(Context ctx, PhpValue /*string|array*/ function, PhpValue /*string|int*/ parameter)
        {
            // resolve RoutineInfo:

            PhpTypeInfo declaringclass = null;
            RoutineInfo routine        = null;

            var function_str = function.AsString();

            if (function_str != null)
            {
                routine = ctx.GetDeclaredFunction(function_str);
            }
            else
            {
                var function_arr = function.AsArray();
                if (function_arr != null && function_arr.Count == 2)
                {
                    declaringclass = ReflectionUtils.ResolvePhpTypeInfo(ctx, function_arr[0]); // cannot be null
                    routine        = declaringclass.RuntimeMethods[function_arr[1].ToStringOrThrow(ctx)];
                }
            }

            if (routine != null)
            {
                var func = (declaringclass == null)
                ? (ReflectionFunctionAbstract) new ReflectionFunction(routine)
                : new ReflectionMethod(declaringclass, routine);

                // resolve parameter:
                var parameters = ReflectionUtils.ResolveReflectionParameters(func, routine.Methods);
                var pstr       = parameter.AsString();
                if (pstr != null)
                {
                    SetParameter(parameters.First(p => p._name == pstr));
                    return;
                }
                else
                {
                    if (parameter.IsLong(out long index) && index < parameters.Count && index >= 0)
                    {
                        SetParameter(parameters[(int)index]);
                        return;
                    }
                }
            }

            throw new ReflectionException();
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Sets variable's type.
        /// </summary>
        /// <param name="ctx">Current runtime context.</param>
        /// <param name="variable">The variable.</param>
        /// <param name="type">The string identifying a new type. See PHP manual for details.</param>
        /// <returns>Whether <paramref name="type"/> is valid type identifier.</returns>
        /// <exception cref="PhpException"><paramref name="type"/> has invalid value.</exception>
        public static bool settype(Context ctx, ref PhpValue variable, string type)
        {
            switch (type.ToLowerInvariant())
            {
            case "bool":
            case "boolean":
                variable = PhpValue.Create(variable.ToBoolean());
                return(true);

            case "int":
            case "integer":
                variable = PhpValue.Create(variable.ToLong());
                return(true);

            case "float":
            case "double":
                variable = PhpValue.Create(variable.ToDouble());
                return(true);

            case "string":
                variable = PhpValue.Create(variable.ToString(ctx));
                return(true);

            case "array":
                variable = PhpValue.Create(variable.AsArray());
                return(true);

            case "object":
                variable = PhpValue.FromClass(variable.ToClass());
                return(true);

            case "null":
                variable = PhpValue.Null;
                return(true);
            }

            //PhpException.InvalidArgument("type", LibResources.GetString("invalid_type_name"));
            //return false;
            throw new ArgumentException(nameof(type));
        }
Ejemplo n.º 7
0
        /// <summary>
        /// Filters a variable with a specified filter.
        /// </summary>
        /// <param name="ctx">Runtime context.</param>
        /// <param name="variable">Value to filter.</param>
        /// <param name="filter">The ID of the filter to apply.</param>
        /// <param name="options">Associative array of options or bitwise disjunction of flags. If filter accepts options, flags can be provided in "flags" field of array. For the "callback" filter, callback type should be passed. The callback must accept one argument, the value to be filtered, and return the value after filtering/sanitizing it.</param>
        /// <returns>Returns the filtered data, or <c>false</c> if the filter fails.</returns>
        public static PhpValue filter_var(Context ctx, PhpValue variable, int filter = FILTER_DEFAULT, PhpValue options = default(PhpValue))
        {
            var      @default    = PhpValue.False; // a default value
            PhpArray options_arr = null;
            long     flags       = 0;

            // process options

            if (options.IsSet)
            {
                options_arr = options.AsArray();
                if (options_arr != null)
                {
                    // [flags]
                    if (options_arr.TryGetValue("flags", out var flagsval))
                    {
                        flagsval.IsLong(out flags);
                    }

                    // [default]
                    if (options_arr.TryGetValue("default", out var defaultval))
                    {
                        @default = defaultval;
                    }

                    // ...
                }
                else
                {
                    options.IsLong(out flags);
                }
            }

            switch (filter)
            {
            //
            // SANITIZE
            //

            case (int)FilterSanitize.FILTER_DEFAULT:
                return((PhpValue)variable.ToString(ctx));

            case (int)FilterSanitize.EMAIL:
                // Remove all characters except letters, digits and !#$%&'*+-/=?^_`{|}~@.[].
                return((PhpValue)FilterSanitizeString(variable.ToString(ctx), (c) =>
                                                      (int)c <= 0x7f && (Char.IsLetterOrDigit(c) ||
                                                                         c == '!' || c == '#' || c == '$' || c == '%' || c == '&' || c == '\'' ||
                                                                         c == '*' || c == '+' || c == '-' || c == '/' || c == '=' || c == '!' ||
                                                                         c == '?' || c == '^' || c == '_' || c == '`' || c == '{' || c == '|' ||
                                                                         c == '}' || c == '~' || c == '@' || c == '.' || c == '[' || c == ']')));

            //
            // VALIDATE
            //

            case (int)FilterValidate.URL:
                return(Uri.TryCreate(variable.ToString(ctx), UriKind.Absolute, out var uri)
                        ? (PhpValue)uri.AbsoluteUri
                        : PhpValue.False);

            case (int)FilterValidate.EMAIL:
            {
                var str = variable.ToString(ctx);
                return(RegexUtilities.IsValidEmail(str)
                            ? (PhpValue)str
                            : PhpValue.False);
            }

            case (int)FilterValidate.INT:
            {
                int result;
                if (int.TryParse((PhpVariable.AsString(variable) ?? string.Empty).Trim(), out result))
                {
                    if (Operators.IsSet(options))
                    {
                        PhpException.ArgumentValueNotSupported("options", "!null");
                    }

                    return((PhpValue)result);         // TODO: options: min_range, max_range
                }
                else
                {
                    return(@default);
                }
            }

            case (int)FilterValidate.BOOLEAN:
            {
                if (variable.IsBoolean(out var b))
                {
                    return(b);
                }

                var varstr = variable.ToString(ctx);

                // TRUE for "1", "true", "on" and "yes".

                if (varstr.EqualsOrdinalIgnoreCase("1") ||
                    varstr.EqualsOrdinalIgnoreCase("true") ||
                    varstr.EqualsOrdinalIgnoreCase("on") ||
                    varstr.EqualsOrdinalIgnoreCase("yes"))
                {
                    return(PhpValue.True);
                }

                //
                if ((flags & FILTER_NULL_ON_FAILURE) == FILTER_NULL_ON_FAILURE)
                {
                    // FALSE is for "0", "false", "off", "no", and "",
                    // NULL for all non-boolean values

                    if (varstr.Length == 0 ||
                        varstr.EqualsOrdinalIgnoreCase("0") ||
                        varstr.EqualsOrdinalIgnoreCase("false") ||
                        varstr.EqualsOrdinalIgnoreCase("off"))
                    {
                        return(PhpValue.False);
                    }
                    else
                    {
                        return(PhpValue.Null);
                    }
                }
                else
                {
                    // FALSE otherwise
                    return(PhpValue.False);
                }
            }

            case (int)FilterValidate.REGEXP:
            {
                // options = options['regexp']
                if (options_arr != null &&
                    options_arr.TryGetValue("regexp", out var regexpval))
                {
                    if (PCRE.preg_match(ctx, regexpval.ToString(ctx), variable.ToString(ctx)) > 0)
                    {
                        return(variable);
                    }
                }
                else
                {
                    PhpException.InvalidArgument("options", string.Format(Resources.LibResources.option_missing, "regexp"));
                }

                return(PhpValue.False);
            }

            default:
                PhpException.ArgumentValueNotSupported(nameof(filter), filter);
                break;
            }

            return(PhpValue.False);
        }
Ejemplo n.º 8
0
        static PhpValue PregReplaceInternal(Context ctx, PhpValue pattern, PhpValue replacement, PhpValue subject, long limit, out long count, bool filter)
        {
            count = 0;

            // PHP's behaviour for undocumented limit range
            if (limit < -1)
            {
                limit = 0;
            }

            // TODO: PHP enumerates subjects first, then patterns and replacements
            //if (subject.IsPhpArray(out var subject_array))
            //{
            //    // returning PhpArray
            //    var s = subject_array.GetFastEnumerator();
            //    while (s.MoveNext())
            //    {
            //    }
            //}
            //else
            //{
            //    // returning string|PhpString|NULL
            //    var s = subject.ToStringOrThrow(ctx);
            //}

            //
            var replacement_array = replacement.AsArray();
            var pattern_array     = pattern.AsArray();

            if (pattern_array == null)
            {
                if (replacement_array == null)
                {
                    // string pattern
                    // string replacement

                    return(PregReplaceInternal(ctx, pattern.ToStringOrThrow(ctx), replacement.ToStringOrThrow(ctx), null, subject, (int)limit, ref count, filter));
                }
                else
                {
                    // string pattern and array replacement not allowed:
                    PhpException.InvalidArgument(nameof(replacement), LibResources.replacement_array_pattern_not);
                    return(PhpValue.Null);
                }
            }
            else if (replacement_array == null)
            {
                // array  pattern
                // string replacement

                var replacement_string = replacement.ToStringOrThrow(ctx);

                var pattern_enumerator = pattern_array.GetFastEnumerator();
                while (pattern_enumerator.MoveNext())
                {
                    subject = PregReplaceInternal(ctx, pattern_enumerator.CurrentValue.ToStringOrThrow(ctx), replacement_string,
                                                  null, subject, (int)limit, ref count, filter);
                }

                //
                return(subject);
            }
            else
            {
                // array pattern
                // array replacement

                var replacement_enumerator = replacement_array.GetFastEnumerator();

                bool   replacement_valid = true;
                string replacement_string;

                var pattern_enumerator = pattern_array.GetFastEnumerator();
                while (pattern_enumerator.MoveNext())
                {
                    // replacements are in array, move to next item and take it if possible, in other case take empty string:
                    if (replacement_valid && replacement_enumerator.MoveNext())
                    {
                        replacement_string = replacement_enumerator.CurrentValue.ToStringOrThrow(ctx);
                    }
                    else
                    {
                        replacement_string = string.Empty;
                        replacement_valid  = false; // end of replacement_enumerator, do not call MoveNext again!
                    }

                    subject = PregReplaceInternal(ctx, pattern_enumerator.CurrentValue.ToStringOrThrow(ctx), replacement_string,
                                                  null, subject, (int)limit, ref count, filter);
                }

                //
                return(subject);
            }
        }
Ejemplo n.º 9
0
        /// <summary>
        /// Filters a variable with a specified filter.
        /// </summary>
        /// <param name="ctx">Runtime context.</param>
        /// <param name="variable">Value to filter.</param>
        /// <param name="filter">The ID of the filter to apply.</param>
        /// <param name="options">Associative array of options or bitwise disjunction of flags. If filter accepts options, flags can be provided in "flags" field of array. For the "callback" filter, callback type should be passed. The callback must accept one argument, the value to be filtered, and return the value after filtering/sanitizing it.</param>
        /// <returns>Returns the filtered data, or <c>false</c> if the filter fails.</returns>
        public static PhpValue filter_var(Context ctx, PhpValue variable, int filter = FILTER_DEFAULT, PhpValue options = default(PhpValue))
        {
            var      @default    = PhpValue.False; // a default value
            PhpArray options_arr = null;
            long     flags       = 0;

            // process options

            if (Operators.IsSet(options))
            {
                options_arr = options.AsArray();
                if (options_arr != null)
                {
                    // [flags]
                    if (options_arr.TryGetValue("flags", out var flagsval))
                    {
                        flagsval.IsLong(out flags);
                    }

                    // [options] => { "min_range" => ??, "default" => ?? }
                    if (options_arr.TryGetValue("options", out var optionsval) && optionsval.IsPhpArray(out var opts_arr))
                    {
                        // [default]
                        if (opts_arr.TryGetValue("default", out var defaultval))
                        {
                            @default = defaultval;
                        }
                    }
                }
                else
                {
                    options.IsLong(out flags);
                }
            }

            switch (filter)
            {
            //
            // SANITIZE
            //

            case (int)FilterSanitize.FILTER_DEFAULT:
                return((PhpValue)variable.ToString(ctx));

            case (int)FilterSanitize.EMAIL:
                // Remove all characters except letters, digits and !#$%&'*+-/=?^_`{|}~@.[].
                return((PhpValue)FilterSanitizeString(variable.ToString(ctx), (c) =>
                                                      (int)c <= 0x7f && (Char.IsLetterOrDigit(c) ||
                                                                         c == '!' || c == '#' || c == '$' || c == '%' || c == '&' || c == '\'' ||
                                                                         c == '*' || c == '+' || c == '-' || c == '/' || c == '=' || c == '!' ||
                                                                         c == '?' || c == '^' || c == '_' || c == '`' || c == '{' || c == '|' ||
                                                                         c == '}' || c == '~' || c == '@' || c == '.' || c == '[' || c == ']')));

            //
            // VALIDATE
            //

            case (int)FilterValidate.URL:

                // TODO: protocol may be ommited, try to add "http://" if fails

                if (Uri.TryCreate(variable.ToString(ctx), UriKind.Absolute, out var uri))
                {
                    if (uri.IsFile && !uri.OriginalString.StartsWith(uri.Scheme, StringComparison.OrdinalIgnoreCase))
                    {
                        // quick check the file:// was just added on linux impl. of Uri.Parse
                        return(@default);
                    }

                    if (flags != 0)
                    {
                        // CONSIDER: rather use `Web.parse_url()` ...
                        var uriflags = (FilterFlag)flags;
                        //if ((uriflags & FilterFlag.PATH_REQUIRED) == FilterFlag.PATH_REQUIRED && ...)
                    }

                    return(uri.AbsoluteUri);
                }
                return(@default);

            case (int)FilterValidate.EMAIL:
            {
                return(variable.IsString(out var str) && RegexUtilities.IsValidEmail(str)
                            ? (PhpValue)str
                            : @default);
            }

            case (int)FilterValidate.IP:
                if (System.Net.IPAddress.TryParse(variable.ToString(ctx), out var addr))
                {
                    if (flags != 0)
                    {
                        // validate flags:
                        if ((addr.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6 && (flags & (int)FilterFlag.IPV6) == 0) ||
                            (addr.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork && (flags & (int)FilterFlag.IPV4) == 0))
                        {
                            return(@default);
                        }

                        if ((flags & (int)FilterFlag.NO_PRIV_RANGE) == (int)FilterFlag.NO_PRIV_RANGE)
                        {
                            /*
                             * Fails validation for the IPv4 ranges: 10.0.0.0/8, 172.16.0.0/12 and 192.168.0.0/16.
                             * Fails validation for the IPv6 addresses starting with FD or FC.
                             */
                            throw new NotImplementedException();
                        }

                        if ((flags & (int)FilterFlag.NO_PRIV_RANGE) == (int)FilterFlag.NO_RES_RANGE)
                        {
                            /*
                             * Fails validation for IPv4 ranges: 0.0.0.0/8, 169.254.0.0/16, 127.0.0.0/8 and 240.0.0.0/4.
                             * Fails validation for IPv6 ranges: ::1/128, ::/128, ::ffff:0:0/96 and fe80::/10.
                             */
                            throw new NotImplementedException();
                        }
                    }

                    return(addr.ToString());
                }
                else
                {
                    return(@default);
                }

            case (int)FilterValidate.INT:
            {
                int result;
                if (int.TryParse((PhpVariable.AsString(variable) ?? string.Empty).Trim(), out result))
                {
                    if (Operators.IsSet(options))
                    {
                        PhpException.ArgumentValueNotSupported("options", "!null");
                    }

                    return((PhpValue)result);         // TODO: options: min_range, max_range
                }
                else
                {
                    return(@default);
                }
            }

            case (int)FilterValidate.BOOLEAN:
            {
                if (variable.IsBoolean(out var b))
                {
                    return(b);
                }

                var varstr = variable.ToString(ctx);

                // TRUE for "1", "true", "on" and "yes".

                if (varstr.EqualsOrdinalIgnoreCase("1") ||
                    varstr.EqualsOrdinalIgnoreCase("true") ||
                    varstr.EqualsOrdinalIgnoreCase("on") ||
                    varstr.EqualsOrdinalIgnoreCase("yes"))
                {
                    return(PhpValue.True);
                }

                //
                if ((flags & FILTER_NULL_ON_FAILURE) == FILTER_NULL_ON_FAILURE)
                {
                    // FALSE is for "0", "false", "off", "no", and "",
                    // NULL for all non-boolean values

                    if (varstr.Length == 0 ||
                        varstr.EqualsOrdinalIgnoreCase("0") ||
                        varstr.EqualsOrdinalIgnoreCase("false") ||
                        varstr.EqualsOrdinalIgnoreCase("off"))
                    {
                        return(PhpValue.False);
                    }
                    else
                    {
                        return(PhpValue.Null);
                    }
                }
                else
                {
                    // FALSE otherwise
                    return(PhpValue.False);
                }
            }

            case (int)FilterValidate.REGEXP:
            {
                // options = options['regexp']
                if (options_arr != null &&
                    options_arr.TryGetValue("regexp", out var regexpval))
                {
                    if (PCRE.preg_match(ctx, regexpval.ToString(ctx), variable.ToString(ctx)) > 0)
                    {
                        return(variable);
                    }
                }
                else
                {
                    PhpException.InvalidArgument("options", string.Format(Resources.LibResources.option_missing, "regexp"));
                }

                return(@default);
            }

            case FILTER_CALLBACK:
                // options = ['options' => $callback]
                if (options_arr != null &&
                    options_arr.TryGetValue("options", out var callbackvar))
                {
                    return(callbackvar.AsCallable().Invoke(ctx, variable));
                }

                return(@default);

            default:
                PhpException.ArgumentValueNotSupported(nameof(filter), filter);
                break;
            }

            return(PhpValue.False);
        }
Ejemplo n.º 10
0
        /// <summary>
        /// Converts the character encoding of <paramref name="str"/> to <paramref name="to_encoding"/>.
        /// </summary>
        /// <param name="ctx">Runtime context.</param>
        /// <param name="str">Input string.</param>
        /// <param name="to_encoding">Target encoding.</param>
        /// <param name="from_encoding">
        /// Encodings to try for decoding <paramref name="str"/>.
        /// It is either an array, or a comma separated enumerated list. If from_encoding is not specified, the internal encoding will be used.
        /// </param>
        /// <returns>Converted string.</returns>
        public static PhpString mb_convert_encoding(Context ctx, PhpString str, string to_encoding, PhpValue from_encoding = default(PhpValue))
        {
            string decoded;

            if (str.ContainsBinaryData)
            {
                // source encoding
                Encoding from_enc = null;
                IEnumerable <Encoding> from_encs = null;

                if (Operators.IsSet(from_encoding))
                {
                    PhpArray from_arr;
                    var      from_str = from_encoding.AsString();
                    if (from_str != null)
                    {
                        // TODO: "auto"

                        if (from_str.IndexOf(',') >= 0)
                        {
                            // comma separated list (string)
                            from_encs = from_str.Split(',').Select(name => name.Trim()).Select(GetEncoding);
                        }
                        else
                        {
                            // string
                            from_enc = GetEncoding(from_str);
                        }
                    }
                    else if ((from_arr = from_encoding.AsArray()) != null)
                    {
                        // array
                        from_encs = from_arr.Values.Select(val => val.ToString().Trim()).Select(GetEncoding);
                    }
                    else
                    {
                        throw new ArgumentException(nameof(from_encoding));
                    }
                }
                else
                {
                    // from_encoding is default or NULL:
                    from_enc = GetConfig(ctx).InternalEncoding ?? ctx.StringEncoding;
                }

                if (from_enc != null)
                {
                    decoded = str.ToString(from_enc);
                }
                else if (from_encs != null)
                {
                    decoded = null;

                    // autodetect encoding
                    foreach (var enc in from_encs)
                    {
                        if (enc != null)
                        {
                            try
                            {
                                decoded = str.ToString(Encoding.GetEncoding(enc.CodePage, EncoderFallback.ExceptionFallback, DecoderFallback.ExceptionFallback));
                                break;
                            }
                            catch
                            {
                                // continue;
                            }
                        }
                    }

                    if (decoded == null)
                    {
                        throw new ArgumentException();
                    }
                }
                else
                {
                    throw new InvalidOperationException();
                }
            }
            else
            {
                // already in UTF16
                decoded = str.ToString();
            }

            // target encoding:
            var target_enc = GetEncoding(to_encoding);

            if (target_enc == null)
            {
                return(new PhpString(decoded));
            }
            else
            {
                return(new PhpString(target_enc.GetBytes(decoded)));
            }
        }
Ejemplo n.º 11
0
        static PhpValue PregReplaceInternal(Context ctx, string pattern, string replacement, IPhpCallable callback, PhpValue subject, int limit, ref long count)
        {
            var regex = new PerlRegex.Regex(pattern);

            // callback
            PerlRegex.MatchEvaluator evaluator = null;
            if (callback != null)
            {
                evaluator = (match) =>
                {
                    var matches_arr = new PhpArray();
                    GroupsToPhpArray(match.PcreGroups, false, matches_arr);

                    return(callback
                           .Invoke(ctx, (PhpValue)matches_arr)
                           .ToStringOrThrow(ctx));
                };
            }

            // TODO: subject as a binary string would be corrupted after Replace - https://github.com/peachpiecompiler/peachpie/issues/178

            //
            var subject_array = subject.AsArray();

            if (subject_array != null)
            {
                var arr = new PhpArray(subject_array.Count);

                var enumerator = subject_array.GetFastEnumerator();
                while (enumerator.MoveNext())
                {
                    var input    = enumerator.CurrentValue;
                    var oldvalue = input.ToStringOrThrow(ctx);
                    var oldcount = count;

                    var newvalue = evaluator == null
                        ? regex.Replace(oldvalue, replacement, limit, ref count)
                        : regex.Replace(oldvalue, evaluator, limit, ref count);

                    // - quick workaround for https://github.com/peachpiecompiler/peachpie/issues/178
                    // - use the original value if possible (mem perf.)

                    arr[enumerator.CurrentKey] = (oldcount == count)
                        ? (input.IsBinaryString(out var bstring) ? bstring.DeepCopy() : oldvalue)
                        : newvalue;
                }

                return(arr);
            }
            else
            {
                var oldvalue = subject.ToStringOrThrow(ctx);
                var oldcount = count;

                var newvalue = evaluator == null
                        ? regex.Replace(oldvalue, replacement, limit, ref count)
                        : regex.Replace(oldvalue, evaluator, limit, ref count);

                // - quick workaround for https://github.com/peachpiecompiler/peachpie/issues/178
                // - use the original value if possible (mem perf.)

                return((oldcount == count)
                    ? (subject.IsBinaryString(out var bstring) ? bstring.DeepCopy() : oldvalue)
                    : newvalue);
            }
        }