From b32be8ebf5e77c1ee9c8d6015a34e7e31b8423c8 Mon Sep 17 00:00:00 2001 From: Benjamin Barenblat Date: Fri, 12 Feb 2016 22:18:46 -0500 Subject: Initial commit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Create a utility to demonstrate scoville’s escaping scheme. --- .gitignore | 13 ++++++ CMakeLists.txt | 32 +++++++++++++++ src/CMakeLists.txt | 46 +++++++++++++++++++++ src/scoville.cc | 117 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 208 insertions(+) create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 src/CMakeLists.txt create mode 100644 src/scoville.cc diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..995babd --- /dev/null +++ b/.gitignore @@ -0,0 +1,13 @@ +# Editor backup files +*~ +\#* +.\#* + +# CMake +Debug/ +Release/ + + +# Local Variables: +# mode: conf +# End: diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..785bad0 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,32 @@ +# Copyright 2016 Benjamin Barenblat +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. + +cmake_policy(VERSION 3.0.2) +cmake_minimum_required(VERSION 3.0) + +project( + scoville + VERSION 0.0.0 + LANGUAGES CXX +) + +set(CMAKE_CXX_COMPILER clang++) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_FORTIFY_SOURCE=2") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ftrapv") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fstack-protector-strong --param=ssp-buffer-size=4") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Weverything -Wno-c++98-compat") + +add_subdirectory(src) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..751bd39 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,46 @@ +# Copyright 2016 Benjamin Barenblat +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. + +include(FindPkgConfig) + +pkg_check_modules(FUSE REQUIRED fuse) +pkg_check_modules(GLOG REQUIRED libglog) + +link_directories( + ${FUSE_LIBRARY_DIRS} + ${GLOG_LIBRARY_DIRS} +) +set( + CMAKE_CXX_FLAGS + "${CMAKE_CXX_FLAGS} ${FUSE_CFLAGS_OTHER} ${GLOG_CFLAGS_OTHER}" +) +set( + CMAKE_EXE_LINKER_FLAGS + "${CMAKE_EXE_LINKER_FLAGS} ${FUSE_LDFLAGS_OTHER} ${GLOG_LDFLAGS_OTHER}" +) + +add_executable( + scoville + scoville.cc +) +target_include_directories( + scoville + PRIVATE ${FUSE_INCLUDE_DIRS} + PRIVATE ${GLOG_INCLUDE_DIRS} +) +target_link_libraries( + scoville + ${FUSE_LIBRARIES} + ${GLOG_LIBRARIES} +) diff --git a/src/scoville.cc b/src/scoville.cc new file mode 100644 index 0000000..c0d4d79 --- /dev/null +++ b/src/scoville.cc @@ -0,0 +1,117 @@ +// Copyright 2016 Benjamin Barenblat +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. + +#include +#include +#include +#include +#include + +#include + +namespace { + +class EncodingFailure : public std::logic_error { + public: + using std::logic_error::logic_error; +}; + +class DecodingFailure : public std::logic_error { + public: + using std::logic_error::logic_error; +}; + +void WriteAsciiAsHex(const char c, std::ostringstream* const out) { + if (1 < sizeof(c) && 0x100 <= c) { + // Not ASCII! + throw EncodingFailure("could not encode non-ASCII character '" + + std::string(1, c) + "'"); + } + *out << std::hex << static_cast(c); +} + +char ReadHexAsAscii(std::istringstream* const in) { + std::array hex_str; + in->get(hex_str.data(), hex_str.size()); + char* decoded_end; + const char result = + static_cast(std::strtol(hex_str.data(), &decoded_end, 16)); + if (decoded_end == hex_str.data()) { + throw DecodingFailure("could not decode invalid hex"); + } + return result; +} + +bool IsVfatBadCharacter(const char c) noexcept { + return (0 <= c && c < 0x20) || c == '*' || c == '?' || c == '<' || c == '>' || + c == '|' || c == '"' || c == ':' || c == '/' || c == '\\'; +} + +void Encode(std::istringstream* const in, std::ostringstream* const out) { + char c; + while (!in->get(c).eof()) { + if (IsVfatBadCharacter(c)) { + *out << '%'; + WriteAsciiAsHex(c, out); + } else if (c == '%') { + *out << "%%"; + } else { + *out << c; + } + } +} + +void Decode(std::istringstream* const in, std::ostringstream* const out) { + char c; + while (!in->get(c).eof()) { + if (c == '%') { + if (in->peek() == '%') { + in->ignore(); + *out << "%"; + } else { + *out << ReadHexAsAscii(in); + } + } else { + *out << c; + } + } +} + +} // namespace + +int main(int, char* const argv[]) { + FLAGS_logtostderr = true; + google::InstallFailureSignalHandler(); + google::InitGoogleLogging(argv[0]); + + LOG(INFO) << "Got " << argv[1]; + + std::string result; + { + std::istringstream in(argv[1]); + std::ostringstream out; + Encode(&in, &out); + result = out.str(); + } + LOG(INFO) << "Encoded to " << result; + + { + std::istringstream in(result); + std::ostringstream out; + Decode(&in, &out); + result = out.str(); + } + LOG(INFO) << "Decoded to " << result; + return 0; +} -- cgit v1.2.3