bool AbstractParser::parseField(StringView words)
{
#define PARSE_FIELD(X) \
    for (const auto x : DEFINED_ROOM_##X##_TYPES) { \
        if (getParserCommandName(x).matches(firstWord)) { \
            setRoomFieldCommand(x, RoomField::X##_TYPE); \
            return true; \
        } \
    }

    if (words.isEmpty())
        return false;

    // REVISIT: support "set room field XXX" ?
    const auto firstWord = words.takeFirstWord();
    if (!words.isEmpty())
        return false;

    PARSE_FIELD(LIGHT);
    PARSE_FIELD(SUNDEATH);
    PARSE_FIELD(PORTABLE);
    PARSE_FIELD(RIDABLE);
    PARSE_FIELD(ALIGN);
    return false;
#undef PARSE
}
void AbstractParser::parseName(StringView view)
{
    if (!view.isEmpty()) {
        auto dir = tryGetDir(view);
        if (!view.isEmpty()) {
            auto name = view.takeFirstWord();
            nameDoorCommand(name.toQString(), dir);
            return;
        }
    }

    showSyntax("name <dir> <name>");
}
Exemple #3
0
IDBKeyPathLexer::TokenType IDBKeyPathLexer::lexIdentifier(String& element)
{
    StringView start = m_remainingText;
    if (!m_remainingText.isEmpty() && isIdentifierStartCharacter(m_remainingText[0]))
        m_remainingText = m_remainingText.substring(1);
    else
        return TokenError;

    while (!m_remainingText.isEmpty() && isIdentifierCharacter(m_remainingText[0]))
        m_remainingText = m_remainingText.substring(1);

    element = start.substring(0, start.length() - m_remainingText.length()).toString();
    return TokenIdentifier;
}
Exemple #4
0
void Settings::remove(const StringView& _name) const
{
	ini_t* ini = INI_T(m_ini);

	FilePath uri(_name);
	const StringView  path     = strTrim(uri.getPath(), "/");
	const StringView& fileName = uri.getFileName();

	int32_t section = INI_GLOBAL_SECTION;

	if (!path.isEmpty() )
	{
		section = ini_find_section(ini, path.getPtr(), path.getLength() );
		if (INI_NOT_FOUND == section)
		{
			section = INI_GLOBAL_SECTION;
		}
	}

	int32_t property = ini_find_property(ini, section, fileName.getPtr(), fileName.getLength() );
	if (INI_NOT_FOUND == property)
	{
		return;
	}

	ini_property_remove(ini, section, property);

	if (INI_GLOBAL_SECTION != section
	&&  0 == ini_property_count(ini, section) )
	{
		ini_section_remove(ini, section);
	}
}
Exemple #5
0
const char* Settings::get(const StringView& _name) const
{
	ini_t* ini = INI_T(m_ini);

	FilePath uri(_name);
	const StringView  path(strTrim(uri.getPath(), "/") );
	const StringView& fileName(uri.getFileName() );
	int32_t section = INI_GLOBAL_SECTION;

	if (!path.isEmpty() )
	{
		section = ini_find_section(ini, path.getPtr(), path.getLength() );
		if (INI_NOT_FOUND == section)
		{
			section = INI_GLOBAL_SECTION;
		}
	}

	int32_t property = ini_find_property(ini, section, fileName.getPtr(), fileName.getLength() );
	if (INI_NOT_FOUND == property)
	{
		return NULL;
	}

	return ini_property_value(ini, section, property);
}
TextEncoding HTMLMetaCharsetParser::encodingFromMetaAttributes(const AttributeList& attributes)
{
    bool gotPragma = false;
    enum { None, Charset, Pragma } mode = None;
    StringView charset;

    for (auto& attribute : attributes) {
        const String& attributeName = attribute.first;
        const String& attributeValue = attribute.second;

        if (attributeName == http_equivAttr) {
            if (equalIgnoringCase(attributeValue, "content-type"))
                gotPragma = true;
        } else if (charset.isEmpty()) {
            if (attributeName == charsetAttr) {
                charset = attributeValue;
                mode = Charset;
            } else if (attributeName == contentAttr) {
                charset = extractCharset(attributeValue);
                if (charset.length())
                    mode = Pragma;
            }
        }
    }

    if (mode == Charset || (mode == Pragma && gotPragma))
        return TextEncoding(stripLeadingAndTrailingHTMLSpaces(charset.toStringWithoutCopying()));

    return TextEncoding();
}
Exemple #7
0
static void setWindowFeature(WindowFeatures& features, StringView key, StringView value)
{
    // Listing a key with no value is shorthand for key=yes
    int numericValue;
    if (value.isEmpty() || equalLettersIgnoringASCIICase(value, "yes"))
        numericValue = 1;
    else
        numericValue = value.toInt();

    // We treat key of "resizable" here as an additional feature rather than setting resizeable to true.
    // This is consistent with Firefox, but could also be handled at another level.

    if (equalLettersIgnoringASCIICase(key, "left") || equalLettersIgnoringASCIICase(key, "screenx"))
        features.x = numericValue;
    else if (equalLettersIgnoringASCIICase(key, "top") || equalLettersIgnoringASCIICase(key, "screeny"))
        features.y = numericValue;
    else if (equalLettersIgnoringASCIICase(key, "width") || equalLettersIgnoringASCIICase(key, "innerwidth"))
        features.width = numericValue;
    else if (equalLettersIgnoringASCIICase(key, "height") || equalLettersIgnoringASCIICase(key, "innerheight"))
        features.height = numericValue;
    else if (equalLettersIgnoringASCIICase(key, "menubar"))
        features.menuBarVisible = numericValue;
    else if (equalLettersIgnoringASCIICase(key, "toolbar"))
        features.toolBarVisible = numericValue;
    else if (equalLettersIgnoringASCIICase(key, "location"))
        features.locationBarVisible = numericValue;
    else if (equalLettersIgnoringASCIICase(key, "status"))
        features.statusBarVisible = numericValue;
    else if (equalLettersIgnoringASCIICase(key, "fullscreen"))
        features.fullscreen = numericValue;
    else if (equalLettersIgnoringASCIICase(key, "scrollbars"))
        features.scrollbarsVisible = numericValue;
    else if (numericValue == 1)
        features.additionalFeatures.append(key.toString());
}
void AbstractParser::parseDirections(StringView view)
{
    if (view.isEmpty())
        showSyntax("dirs [-(name|desc|dyncdesc|note|exits|all)] pattern");
    else
        doGetDirectionsCommand(view);
}
// https://wicg.github.io/entries-api/#resolve-a-relative-path
static String resolveRelativeVirtualPath(StringView baseVirtualPath, StringView relativeVirtualPath)
{
    ASSERT(baseVirtualPath[0] == '/');
    if (!relativeVirtualPath.isEmpty() && relativeVirtualPath[0] == '/')
        return relativeVirtualPath.length() == 1 ? relativeVirtualPath.toString() : resolveRelativeVirtualPath("/", relativeVirtualPath.substring(1));

    Vector<StringView> virtualPathSegments;
    for (auto segment : baseVirtualPath.split('/'))
        virtualPathSegments.append(segment);

    for (auto segment : relativeVirtualPath.split('/')) {
        ASSERT(!segment.isEmpty());
        if (segment == ".")
            continue;
        if (segment == "..") {
            if (!virtualPathSegments.isEmpty())
                virtualPathSegments.removeLast();
            continue;
        }
        virtualPathSegments.append(segment);
    }

    if (virtualPathSegments.isEmpty())
        return "/"_s;

    StringBuilder builder;
    for (auto& segment : virtualPathSegments) {
        builder.append('/');
        builder.append(segment);
    }
    return builder.toString();
}
void AbstractParser::parseSearch(StringView view)
{
    if (view.isEmpty())
        showSyntax("search [-(name|desc|dyncdesc|note|exits|all)] pattern");
    else
        doSearchCommand(view);
}
Exemple #11
0
WindowFeatures parseWindowFeatures(StringView featuresString)
{
    // The IE rule is: all features except for channelmode and fullscreen default to YES, but
    // if the user specifies a feature string, all features default to NO. (There is no public
    // standard that applies to this method.)
    //
    // <http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/open_0.asp>
    // We always allow a window to be resized, which is consistent with Firefox.

    WindowFeatures features;

    if (featuresString.isEmpty())
        return features;

    features.menuBarVisible = false;
    features.statusBarVisible = false;
    features.toolBarVisible = false;
    features.locationBarVisible = false;
    features.scrollbarsVisible = false;

    processFeaturesString(featuresString, [&features](StringView key, StringView value) {
        setWindowFeature(features, key, value);
    });

    return features;
}
bool AbstractParser::parseExitFlag(const ExitFlag flag, StringView words)
{
    const auto dir = tryGetDir(words);
    if (!words.isEmpty())
        return false;
    toggleExitFlagCommand(flag, dir);
    return true;
}
bool AbstractParser::parseLoadFlags(StringView words)
{
    if (words.isEmpty())
        return false;

    const auto firstWord = words.takeFirstWord();
    if (!words.isEmpty())
        return false;

    for (const RoomLoadFlag loadFlag : ALL_LOAD_FLAGS) {
        if (getParserCommandName(loadFlag).matches(firstWord)) {
            toggleRoomFlagCommand(loadFlag, RoomField::LOAD_FLAGS);
            return true;
        }
    }
    return false;
}
bool AbstractParser::parseDoorAction(const DoorActionType dat, StringView words)
{
    const auto dir = tryGetDir(words);
    if (!words.isEmpty())
        return false;
    performDoorCommand(dir, dat);
    return true;
}
void AbstractParser::parseGroupTell(const StringView &view)
{
    if (view.isEmpty())
        sendToUser("What do you want to tell the group?\r\n");
    else {
        emit sendGroupTellEvent(view.toQByteArray());
        sendToUser("OK.\r\n");
    }
}
// https://wicg.github.io/entries-api/#valid-path
static bool isValidVirtualPath(StringView virtualPath)
{
    if (virtualPath.isEmpty())
        return true;
    if (virtualPath[0] == '/') {
        // An absolute path is a string consisting of '/' (U+002F SOLIDUS) followed by one or more path segments joined by '/' (U+002F SOLIDUS).
        return isZeroOrMorePathSegmentsSeparatedBySlashes(virtualPath.substring(1));
    }
    return isValidRelativeVirtualPath(virtualPath);
}
// https://wicg.github.io/entries-api/#relative-path
static bool isValidRelativeVirtualPath(StringView virtualPath)
{
    if (virtualPath.isEmpty())
        return false;

    if (virtualPath[0] == '/')
        return false;

    return isZeroOrMorePathSegmentsSeparatedBySlashes(virtualPath);
}
void AbstractParser::parseSpecialCommand(StringView wholeCommand)
{
    if (wholeCommand.isEmpty())
        throw std::runtime_error("input is empty");

    if (evalSpecialCommandMap(wholeCommand))
        return;

    const auto word = wholeCommand.takeFirstWord();
    sendToUser(QString("Unrecognized command: %1\r\n").arg(word.toQString()));
}
// https://wicg.github.io/entries-api/#path-segment
static bool isValidPathSegment(StringView segment)
{
    if (segment.isEmpty() || segment == "." || segment == "..")
        return true;

    for (unsigned i = 0; i < segment.length(); ++i) {
        if (!isValidPathNameCharacter(segment[i]))
            return false;
    }
    return true;
}
void AbstractParser::parseGroupKick(const StringView &view)
{
    if (view.isEmpty())
        sendToUser("Who do you want to kick from the group?\r\n");
    else {
        // REVISIT: We should change GroupManager to be a "FrontEnd" in this
        // thread and call it directly
        emit sendGroupKickEvent(view.toQByteArray().simplified());
        sendToUser("OK.\r\n");
    }
}
Exemple #21
0
IDBKeyPathLexer::TokenType IDBKeyPathLexer::lex(String& element)
{
    if (m_remainingText.isEmpty())
        return TokenEnd;

    if (m_remainingText[0] == '.') {
        m_remainingText = m_remainingText.substring(1);
        return TokenDot;
    }

    return lexIdentifier(element);
}
bool AbstractParser::parseExitFlags(StringView words)
{
    if (words.isEmpty())
        return false;

    const auto firstWord = words.takeFirstWord();
    for (const ExitFlag flag : ALL_EXIT_FLAGS) {
        if (getParserCommandName(flag).matches(firstWord)) {
            return parseExitFlag(flag, words);
        }
    }
    return false;
}
bool AbstractParser::parseDoorAction(StringView words)
{
    if (words.isEmpty())
        return false;

    const auto firstWord = words.takeFirstWord();
    for (const DoorActionType dat : ALL_DOOR_ACTION_TYPES) {
        if (getParserCommandName(dat).matches(firstWord)) {
            return parseDoorAction(dat, words);
        }
    }
    return false;
}
void AbstractParser::parseSetCommand(StringView view)
{
    if (view.isEmpty()) {
        sendToUser(QString("Syntax: %1set prefix [punct-char]\r\n").arg(prefixChar));
        return;
    }

    auto first = view.takeFirstWord();
    if (Abbrev{"prefix", 3}.matches(first)) {
        if (view.isEmpty()) {
            showCommandPrefix();
            return;
        }

        auto next = view.takeFirstWord();
        if (next.size() == 3) {
            auto quote = next.takeFirstLetter();
            const bool validQuote = quote == '\'' || quote == '"';
            const auto prefix = next.takeFirstLetter().toLatin1();

            if (validQuote && isValidPrefix(prefix) && quote == next.takeFirstLetter()
                && quote != prefix && setCommandPrefix(prefix)) {
                return;
            }
        } else if (next.size() == 1) {
            const auto prefix = next.takeFirstLetter().toLatin1();
            if (setCommandPrefix(prefix)) {
                return;
            }
        }

        sendToUser("Invalid prefix.\r\n");
        return;
    }

    sendToUser("That variable is not supported.");
}
void AbstractParser::parseHelp(StringView words)
{
    if (words.isEmpty()) {
        showHelp();
        return;
    }

    auto next = words.takeFirstWord();

    if (Abbrev{"abbreviations", 2}.matches(next)) {
        showHelpCommands(true);
        return;
    } else if (Abbrev{"commands", 1}.matches(next)) {
        showHelpCommands(false);
        return;
    }

    auto &map = m_specialCommandMap;
    auto name = next.toQString().toStdString();
    auto it = map.find(name);
    if (it != map.end()) {
        it->second.help(name);
        return;
    }

    if (Abbrev{"map", 1}.matches(next))
        showMapHelp();
    else if (Abbrev{"door", 1}.matches(next))
        showDoorCommandHelp();
    else if (Abbrev{"group", 1}.matches(next))
        showGroupHelp();
    else if (Abbrev{"exits", 2}.matches(next))
        showExitHelp();
    else if (Abbrev{"flags", 1}.matches(next))
        showRoomSimpleFlagsHelp();
    else if (Abbrev{"mobiles", 2}.matches(next))
        showRoomMobFlagsHelp();
    else if (Abbrev{"load", 2}.matches(next))
        showRoomLoadFlagsHelp();
    else if (Abbrev{"miscellaneous", 2}.matches(next))
        showMiscHelp();
    else {
        showHelp();
    }
}
bool MultipartHandle::parseHeadersIfPossible()
{
    size_t contentLength = m_buffer.size();

    if (!contentLength)
        return false;

    const char* content = m_buffer.data();

    // Check if we have the header closing strings.
    if (!strnstr(content, "\r\n\r\n", contentLength)) {
        // Some servers closes the headers with only \n-s.
        if (!strnstr(content, "\n\n", contentLength)) {
            // Don't have the header closing string. Wait for more data.
            return false;
        }
    }

    // Parse the HTTP headers.
    String value;
    StringView name;
    char* p = const_cast<char*>(content);
    const char* end = content + contentLength;
    size_t totalConsumedLength = 0;
    for (; p < end; ++p) {
        String failureReason;
        size_t consumedLength = parseHTTPHeader(p, end - p, failureReason, name, value, false);
        if (!consumedLength)
            break; // No more header to parse.

        p += consumedLength;
        totalConsumedLength += consumedLength;

        // The name should not be empty, but the value could be empty.
        if (name.isEmpty())
            break;

        m_headers.add(name.toString(), value);
    }

    m_buffer.remove(0, totalConsumedLength + 1);
    return true;
}
Exemple #27
0
void Settings::set(const StringView& _name, const StringView& _value)
{
	ini_t* ini = INI_T(m_ini);

	FilePath uri(_name);
	const StringView  path(strTrim(uri.getPath(), "/") );
	const StringView& fileName(uri.getFileName() );

	int32_t section = INI_GLOBAL_SECTION;

	if (!path.isEmpty() )
	{
		section = ini_find_section(ini, path.getPtr(), path.getLength() );
		if (INI_NOT_FOUND == section)
		{
			section = ini_section_add(ini, path.getPtr(), path.getLength() );
		}
	}

	int32_t property = ini_find_property(ini, section, fileName.getPtr(), fileName.getLength() );
	if (INI_NOT_FOUND == property)
	{
		ini_property_add(
			  ini
			, section
			, fileName.getPtr()
			, fileName.getLength()
			, _value.getPtr()
			, _value.getLength()
			);
	}
	else
	{
		ini_property_value_set(
			  ini
			, section
			, property
			, _value.getPtr()
			, _value.getLength()
			);
	}
}
CString TextEncoding::encode(StringView text, UnencodableHandling handling) const
{
    if (!m_name)
        return CString();

    if (text.isEmpty())
        return "";

    // FIXME: What's the right place to do normalization?
    // It's a little strange to do it inside the encode function.
    // Perhaps normalization should be an explicit step done before calling encode.

    auto upconvertedCharacters = text.upconvertedCharacters();

    const UChar* source = upconvertedCharacters;
    size_t sourceLength = text.length();

    Vector<UChar> normalizedCharacters;

    UErrorCode err = U_ZERO_ERROR;
    if (unorm_quickCheck(source, sourceLength, UNORM_NFC, &err) != UNORM_YES) {
        // First try using the length of the original string, since normalization to NFC rarely increases length.
        normalizedCharacters.grow(sourceLength);
        int32_t normalizedLength = unorm_normalize(source, sourceLength, UNORM_NFC, 0, normalizedCharacters.data(), sourceLength, &err);
        if (err == U_BUFFER_OVERFLOW_ERROR) {
            err = U_ZERO_ERROR;
            normalizedCharacters.resize(normalizedLength);
            normalizedLength = unorm_normalize(source, sourceLength, UNORM_NFC, 0, normalizedCharacters.data(), normalizedLength, &err);
        }
        ASSERT(U_SUCCESS(err));

        source = normalizedCharacters.data();
        sourceLength = normalizedLength;
    }

    return newTextCodec(*this)->encode(source, sourceLength, handling);
}
bool AbstractParser::parsePrint(StringView &input)
{
    const auto syntax = [this]() { sendToUser("Print what? [dynamic | static | note]\r\n"); };

    if (input.isEmpty()) {
        syntax();
        return true;
    }

    const auto next = input.takeFirstWord();
    if (Abbrev{"dynamic", 1}.matches(next)) {
        printRoomInfo(dynamicRoomFields);
        return true;
    } else if (Abbrev{"static", 1}.matches(next)) {
        printRoomInfo(staticRoomFields);
        return true;
    } else if (Abbrev{"note", 1}.matches(next)) {
        showNote();
        return true;
    } else {
        syntax();
        return true;
    }
}
Exemple #30
0
const char* WebSocketHandshake::readHTTPHeaders(const char* start, const char* end)
{
    StringView name;
    String value;
    bool sawSecWebSocketExtensionsHeaderField = false;
    bool sawSecWebSocketAcceptHeaderField = false;
    bool sawSecWebSocketProtocolHeaderField = false;
    const char* p = start;
    for (; p < end; p++) {
        size_t consumedLength = parseHTTPHeader(p, end - p, m_failureReason, name, value);
        if (!consumedLength)
            return nullptr;
        p += consumedLength;

        // Stop once we consumed an empty line.
        if (name.isEmpty())
            break;

        HTTPHeaderName headerName;
        if (!findHTTPHeaderName(name, headerName)) {
            // Evidence in the wild shows that services make use of custom headers in the handshake
            m_serverHandshakeResponse.addHTTPHeaderField(name.toString(), value);
            continue;
        }

        // https://tools.ietf.org/html/rfc7230#section-3.2.4
        // "Newly defined header fields SHOULD limit their field values to US-ASCII octets."
        if ((headerName == HTTPHeaderName::SecWebSocketExtensions
            || headerName == HTTPHeaderName::SecWebSocketAccept
            || headerName == HTTPHeaderName::SecWebSocketProtocol)
            && !value.containsOnlyASCII()) {
            m_failureReason = makeString(name, " header value should only contain ASCII characters");
            return nullptr;
        }
        
        if (headerName == HTTPHeaderName::SecWebSocketExtensions) {
            if (sawSecWebSocketExtensionsHeaderField) {
                m_failureReason = ASCIILiteral("The Sec-WebSocket-Extensions header must not appear more than once in an HTTP response");
                return nullptr;
            }
            if (!m_extensionDispatcher.processHeaderValue(value)) {
                m_failureReason = m_extensionDispatcher.failureReason();
                return nullptr;
            }
            sawSecWebSocketExtensionsHeaderField = true;
        } else {
            if (headerName == HTTPHeaderName::SecWebSocketAccept) {
                if (sawSecWebSocketAcceptHeaderField) {
                    m_failureReason = ASCIILiteral("The Sec-WebSocket-Accept header must not appear more than once in an HTTP response");
                    return nullptr;
                }
                sawSecWebSocketAcceptHeaderField = true;
            } else if (headerName == HTTPHeaderName::SecWebSocketProtocol) {
                if (sawSecWebSocketProtocolHeaderField) {
                    m_failureReason = ASCIILiteral("The Sec-WebSocket-Protocol header must not appear more than once in an HTTP response");
                    return nullptr;
                }
                sawSecWebSocketProtocolHeaderField = true;
            }

            m_serverHandshakeResponse.addHTTPHeaderField(headerName, value);
        }
    }
    return p;
}