Exemple #1
0
        /// <summary>
        /// Extract a boolean from 'src'
        /// Expects 'src' to point to a string of the following form:
        /// [delim]{0|1|true|false}
        /// The first character that does not fit this form stops the scan.
        /// '0','1' must be followed by a non-identifier character
        /// 'true', 'false' can have any case</summary>
        public static bool Bool(out bool bool_, Src src, string?delim = null)
        {
            bool_ = false;
            delim ??= DefaultDelimiters;

            // Find the first non-delimiter
            if (!AdvanceToNonDelim(src, delim))
            {
                return(false);
            }

            // Extract the boolean
            switch (char.ToLower(src))
            {
            default: return(false);

            case '0': bool_ = false; return(!Str_.IsIdentifier(++src, false));

            case '1': bool_ = true; return(!Str_.IsIdentifier(++src, false));

            case 't': bool_ = true; return(char.ToLower(++src) == 'r' && char.ToLower(++src) == 'u' && char.ToLower(++src) == 'e' && !Str_.IsIdentifier(++src, false));

            case 'f': bool_ = false; return(char.ToLower(++src) == 'a' && char.ToLower(++src) == 'l' && char.ToLower(++src) == 's' && char.ToLower(++src) == 'e' && !Str_.IsIdentifier(++src, false));
            }
        }
Exemple #2
0
        /// <summary>
        /// Construct a preprocessor macro of the form: 'TAG(p0,p1,..,pn)' expansion
        /// from a stream of characters. Stops at the first non-escaped new line</summary>
        public Macro(Src src, Loc loc)
            : this(null, null, null, loc)
        {
            // Extract the tag and find it's hash code
            m_tag = ReadTag(src, loc);

            // Hash the tag
            //	m_hash = Hash(m_tag);

            // Extract the optional parameters
            if (src == '(')
            {
                ReadParams(src, m_params, loc, true);
            }

            // Trim whitespace from before the expansion text
            for (; src != 0 && Str_.IsLineSpace(src); ++src)
            {
            }

            // Extract the expansion and trim all leading and following whitespace
            if (!Extract.Line(out var expansion, src, true))
            {
                throw new ScriptException(EResult.InvalidMacroDefinition, loc, "invalid macro expansion");
            }

            m_expansion = expansion.Trim();
        }
Exemple #3
0
        /// <summary>
        /// Expands the macro into the string 'exp' with the text of this macro including substituted parameter text.</summary>
        private string Expand(List <string> args, Loc location)
        {
            if (args.Count != m_params.Count)
            {
                throw new ScriptException(EResult.ParameterCountMismatch, location, "macro parameter count mismatch");
            }

            // Set the string to the macro text initially
            var exp = new StringBuilder(m_expansion);

            // Substitute each parameter
            for (int i = 0; i != m_params.Count; ++i)
            {
                var what = m_params[i];
                if (what.Length == 0)
                {
                    continue;
                }
                var len = what.Length;

                // Replace the instances of 'what' with 'with'
                string with;
                for (int j = Str_.IndexOfIdentifier(exp.ToString(), what, 0); j != exp.Length; j = Str_.IndexOfIdentifier(exp.ToString(), what, j += len))
                {
                    // If the identifier is prefixed with '##' then just remove the '##'
                    // this will have the effect of concatenating the substituted strings.
                    if (j >= 2 && exp[j - 1] == '#' && exp[j - 2] == '#')
                    {
                        j   -= 2;
                        len += 2;
                        with = args[i];
                    }

                    // If the identifier is prefixed with '#' then replace 'what' with 'with' as a literal string
                    else if (j >= 1 && exp[j - 1] == '#')
                    {
                        j   -= 1; len += 1;
                        with = args[i];
                        with.Replace("\"", "\\\"");
                        with = with.Quotes(add: true);
                    }

                    // Otherwise, normal substitution
                    else
                    {
                        with = args[i];
                    }

                    // Do the substitution
                    exp.Remove(j, len);
                    exp.Insert(j, with);
                    j += with.Length - len;
                }
            }

            return(exp.ToString());
        }
Exemple #4
0
        /// <summary>Decode byte data from a registry key</summary>
        public static object?Decode(RegistryValueKind kind, byte[] data)
        {
            switch (kind)
            {
            case RegistryValueKind.None:
            {
                return(null);
            }

            case RegistryValueKind.Unknown:
            {
                return(data);
            }

            case RegistryValueKind.String:
            {
                return(Encoding.Unicode.GetString(data, 0, data.Length).TrimEnd('\0'));
            }

            case RegistryValueKind.ExpandString:
            {
                var re  = new Regex("%(.*?)%", RegexOptions.None);
                var str = Encoding.Unicode.GetString(data, 0, data.Length).TrimEnd('\0');
                return(re.Replace(str, m => Environment.GetEnvironmentVariable(m.Groups[1].Value)));
            }

            case RegistryValueKind.Binary:
            {
                return(data);
            }

            case RegistryValueKind.DWord:
            {
                return(BitConverter.ToUInt32(data, 0));
            }

            case RegistryValueKind.MultiString:
            {
                var multi_str = Encoding.Unicode.GetString(data, 0, data.Length);
                var strings   = Str_.DecodeStringArray(multi_str);
                return(strings);
            }

            case RegistryValueKind.QWord:
            {
                return(BitConverter.ToUInt64(data, 0));
            }

            default:
            {
                throw new Exception($"Registry property kind {kind} unsupported");
            }
            }
        }
Exemple #5
0
        /// <summary>Extract a contiguous block of identifier characters from 'src' incrementing 'src'</summary>
        public static bool Identifier(out string id, Src src, string?delim = null)
        {
            id = string.Empty;
            delim ??= DefaultDelimiters;

            // Find the first non-delimiter
            if (!AdvanceToNonDelim(src, delim))
            {
                return(false);
            }

            // If the first non-delimiter is not a valid identifier character, then we can't extract an identifier
            if (!Str_.IsIdentifier(src, true))
            {
                return(false);
            }

            // Copy up to the first non-identifier character
            BufferWhile(src, (s, i) => Str_.IsIdentifier(s[i], false) ? 1 : 0, 1, out var len);
            id   = src.Buffer.ToString(0, len);
            src += len;
            return(true);
        }
Exemple #6
0
        public static bool String(out string str, Src src, char escape, string?quotes = null, string?delim = null)
        {
            str = string.Empty;
            delim ??= DefaultDelimiters;

            // Set the accepted quote characters
            quotes ??= "\"\'";

            // Find the first non-delimiter
            if (!AdvanceToNonDelim(src, delim))
            {
                return(false);
            }

            // If the next character is not an acceptable quote, then this isn't a string
            char quote = src;

            if (quotes.Contains(quote))
            {
                ++src;
            }
            else
            {
                return(false);
            }

            // Copy the string
            var sb = new StringBuilder();

            if (escape != 0)
            {
                // Copy to the closing quote, allowing for the escape character
                for (; src != 0 && src != quote; ++src)
                {
                    if (src == escape)
                    {
                        switch (++src)
                        {
                        default: break;

                        case 'a':  sb.Append('\a'); break;

                        case 'b':  sb.Append('\b'); break;

                        case 'f':  sb.Append('\f'); break;

                        case 'n':  sb.Append('\n'); break;

                        case 'r':  sb.Append('\r'); break;

                        case 't':  sb.Append('\t'); break;

                        case 'v':  sb.Append('\v'); break;

                        case '\'': sb.Append('\''); break;

                        case '\"': sb.Append('\"'); break;

                        case '\\': sb.Append('\\'); break;

                        case '0':
                        case '1':
                        case '2':
                        case '3':
                        {
                            // ASCII character in octal
                            var oct = new char[8]; var i = 0;
                            for (; i != oct.Length && Str_.IsOctDigit(src); ++i, ++src)
                            {
                                oct[i] = src;
                            }
                            sb.Append((char)Convert.ToInt32(new string(oct, 0, i), 8));
                            break;
                        }

                        case 'x':
                        {
                            // ASCII or UNICODE character in hex
                            var hex = new char[8]; var i = 0;
                            for (; i != hex.Length && Str_.IsHexDigit(src); ++i, ++src)
                            {
                                hex[i] = src;
                            }
                            sb.Append((char)Convert.ToInt32(new string(hex, 0, i), 16));
                            break;
                        }
                        }
                    }
                    else
                    {
                        sb.Append(src);
                    }
                }
            }
            else
            {
                // Copy to the next quote
                for (; src != 0 && src != quote; ++src)
                {
                    sb.Append(src);
                }
            }

            // If the string doesn't end with a quote, then it's not a valid string
            if (src == quote)
            {
                ++src;
            }
            else
            {
                return(false);
            }
            str = sb.ToString();
            return(true);
        }
Exemple #7
0
        /// <summary>
        /// Extract a comma separated parameter list of the form '(p0,p1,..,pn)'
        /// If 'identifiers' is true then the parameters are expected to be identifiers.
        /// If not, then anything delimited by commas is accepted. 'identifiers' == true is used when
        /// reading the definition of the macro, 'identifiers' == false is used when expanding an instance.
        /// If an empty parameter list is given, i.e. "()" then 'args' is returned containing one blank parameter.
        /// Returns true if the macro does not take parameters or the correct number of parameters where given,
        /// false if the macro takes parameters but none were given. Basically, 'false' means, don't treat
        /// this macro as matching because no params were given. If false is returned the buffer will
        /// contain anything read during this method.</summary>
        private bool ReadParams(Src buf, List <string> args, Loc location, bool identifiers)
        {
            // Buffer up to the first non-whitespace character
            // If no parameters are given, then the macro doesn't match
            if (!identifiers && args.Count != 0)
            {
                int i = 0; for (; Str_.IsWhiteSpace(buf[i]); ++i)
                {
                }
                if (buf[i] != '(')
                {
                    return(false);
                }
                buf += i;
            }

            // If we're not reading the parameter names for a macro definition
            // and the macro takes no parameters, then ReadParams is a no-op
            if (!identifiers && m_params.Count == 0)
            {
                return(true);
            }

            // Capture the strings between commas as the parameters
            for (++buf; buf != ')'; buf += buf != ')' ? 1 : 0)
            {
                // Read parameter names for a macro definition
                if (identifiers)
                {
                    if (!Extract.Identifier(out var arg, buf))
                    {
                        throw new ScriptException(EResult.InvalidIdentifier, location, "invalid macro identifier");
                    }
                    args.Add(arg);
                }

                // Read parameters being passed to the macro
                else
                {
                    var arg = new StringBuilder();
                    for (int nest = 0; (buf != ',' && buf != ')') || nest != 0; ++buf)
                    {
                        if (buf == 0)
                        {
                            throw new ScriptException(EResult.UnexpectedEndOfFile, location, "macro parameter list incomplete");
                        }
                        arg.Append(buf);
                        nest += buf == '(' ? 1 : 0;
                        nest -= buf == ')' ? 1 : 0;
                    }
                    args.Add(arg.ToString());
                }
            }
            ++buf;             // Skip over the ')'

            // Add a blank argument to distinguish between "TAG()" and "TAG"
            if (args.Count == 0)
            {
                args.Add(string.Empty);
            }

            // Check enough parameters have been given
            if (!identifiers && m_params.Count != args.Count)
            {
                throw new ScriptException(EResult.ParameterCountMismatch, location, "incorrect number of macro parameters");
            }

            return(true);
        }