├── .gitignore ├── .idea ├── .gitignore ├── .name ├── codeStyles │ ├── Project.xml │ └── codeStyleConfig.xml ├── misc.xml ├── modules.xml ├── pass-fdo-secrets.iml └── vcs.xml ├── CMakeLists.txt ├── LICENSE ├── README.md ├── TODO.md ├── adaptors ├── collectionadaptor.h ├── itemadaptor.h ├── promptadaptor.h ├── secretsadaptor.h └── sessionadaptor.h ├── impl ├── Collection.cpp ├── Collection.h ├── CollectionProxy.cpp ├── CollectionProxy.h ├── Item.cpp ├── Item.h ├── ItemProxy.cpp ├── ItemProxy.h ├── SecretService.cpp ├── SecretService.h ├── Session.cpp ├── Session.h └── sessions │ ├── Plain.cpp │ ├── Plain.h │ └── sessions.h ├── include ├── nanoid │ ├── crypto_random.h │ ├── nanoid.h │ └── settings.h ├── rapidjson │ ├── allocators.h │ ├── cursorstreamwrapper.h │ ├── document.h │ ├── encodedstream.h │ ├── encodings.h │ ├── error │ │ ├── en.h │ │ └── error.h │ ├── filereadstream.h │ ├── filewritestream.h │ ├── fwd.h │ ├── internal │ │ ├── biginteger.h │ │ ├── clzll.h │ │ ├── diyfp.h │ │ ├── dtoa.h │ │ ├── ieee754.h │ │ ├── itoa.h │ │ ├── meta.h │ │ ├── pow10.h │ │ ├── regex.h │ │ ├── stack.h │ │ ├── strfunc.h │ │ ├── strtod.h │ │ └── swap.h │ ├── istreamwrapper.h │ ├── memorybuffer.h │ ├── memorystream.h │ ├── msinttypes │ │ ├── inttypes.h │ │ └── stdint.h │ ├── ostreamwrapper.h │ ├── pointer.h │ ├── prettywriter.h │ ├── rapidjson.h │ ├── reader.h │ ├── schema.h │ ├── stream.h │ ├── stringbuffer.h │ └── writer.h └── subprocess.h ├── install ├── arch │ └── PKGBUILD ├── pass-secrets.service.in └── si.nullob.pass-secrets.service.in ├── interop ├── DocumentHelper.cpp ├── DocumentHelper.h ├── PassCollection.cpp ├── PassCollection.h ├── PassItem.cpp ├── PassItem.h ├── PassStore.cpp └── PassStore.h ├── introspection ├── collection.xml ├── item.xml ├── prompt.xml ├── secrets.xml └── session.xml ├── main.cpp └── nanoid_cpp ├── .gitignore ├── .travis.yml ├── CMakeLists.txt ├── LICENSE ├── README.md ├── src └── nanoid │ ├── crypto_random.cpp │ └── nanoid.cpp └── tests └── unit_tests.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider 2 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 3 | 4 | # User-specific stuff 5 | .idea/**/workspace.xml 6 | .idea/**/tasks.xml 7 | .idea/**/usage.statistics.xml 8 | .idea/**/dictionaries 9 | .idea/**/shelf 10 | 11 | build/ 12 | 13 | # Generated files 14 | .idea/**/contentModel.xml 15 | 16 | # Sensitive or high-churn files 17 | .idea/**/dataSources/ 18 | .idea/**/dataSources.ids 19 | .idea/**/dataSources.local.xml 20 | .idea/**/sqlDataSources.xml 21 | .idea/**/dynamic.xml 22 | .idea/**/uiDesigner.xml 23 | .idea/**/dbnavigator.xml 24 | 25 | # Gradle 26 | .idea/**/gradle.xml 27 | .idea/**/libraries 28 | 29 | # Gradle and Maven with auto-import 30 | # When using Gradle or Maven with auto-import, you should exclude module files, 31 | # since they will be recreated, and may cause churn. Uncomment if using 32 | # auto-import. 33 | # .idea/artifacts 34 | # .idea/compiler.xml 35 | # .idea/jarRepositories.xml 36 | # .idea/modules.xml 37 | # .idea/*.iml 38 | # .idea/modules 39 | # *.iml 40 | # *.ipr 41 | 42 | # CMake 43 | cmake-build-*/ 44 | 45 | # Mongo Explorer plugin 46 | .idea/**/mongoSettings.xml 47 | 48 | # File-based project format 49 | *.iws 50 | 51 | # IntelliJ 52 | out/ 53 | 54 | # mpeltonen/sbt-idea plugin 55 | .idea_modules/ 56 | 57 | # JIRA plugin 58 | atlassian-ide-plugin.xml 59 | 60 | # Cursive Clojure plugin 61 | .idea/replstate.xml 62 | 63 | # Crashlytics plugin (for Android Studio and IntelliJ) 64 | com_crashlytics_export_strings.xml 65 | crashlytics.properties 66 | crashlytics-build.properties 67 | fabric.properties 68 | 69 | # Editor-based Rest Client 70 | .idea/httpRequests 71 | 72 | # Android studio 3.1+ serialized cache file 73 | .idea/caches/build_file_checksums.ser 74 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Datasource local storage ignored files 5 | /dataSources/ 6 | /dataSources.local.xml 7 | # Editor-based HTTP Client requests 8 | /httpRequests/ 9 | -------------------------------------------------------------------------------- /.idea/.name: -------------------------------------------------------------------------------- 1 | pass-secrets -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 36 | 37 | -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/pass-fdo-secrets.iml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.15) 2 | 3 | if (NOT DEFINED CMAKE_INSTALL_PREFIX) 4 | set (CMAKE_INSTALL_PREFIX "/usr/local" CACHE PATH "Install to /usr/local" FORCE) 5 | endif() 6 | 7 | configure_file(install/si.nullob.pass-secrets.service.in si.nullob.pass-secrets.service) 8 | install(FILES ${CMAKE_CURRENT_BINARY_DIR}/si.nullob.pass-secrets.service DESTINATION share/dbus-1/services) 9 | 10 | configure_file(install/pass-secrets.service.in pass-secrets.service) 11 | install(FILES ${CMAKE_CURRENT_BINARY_DIR}/pass-secrets.service DESTINATION lib/systemd/user) 12 | 13 | project(pass-secrets) 14 | 15 | set(CMAKE_CXX_STANDARD 17) 16 | 17 | include_directories("include") 18 | add_subdirectory("nanoid_cpp") 19 | 20 | find_package(sdbus-c++ REQUIRED) 21 | 22 | add_executable(pass-secrets main.cpp impl/SecretService.cpp impl/SecretService.h impl/Session.cpp impl/Session.h interop/PassStore.cpp interop/PassStore.h interop/PassCollection.cpp interop/PassCollection.h interop/PassItem.cpp interop/PassItem.h interop/DocumentHelper.h interop/DocumentHelper.cpp impl/Collection.cpp impl/Collection.h impl/Item.cpp impl/Item.h impl/CollectionProxy.cpp impl/CollectionProxy.h impl/ItemProxy.cpp impl/ItemProxy.h impl/sessions/Plain.cpp impl/sessions/Plain.h impl/sessions/sessions.h) 23 | target_link_libraries(pass-secrets PRIVATE SDBusCpp::sdbus-c++ nanoid) 24 | target_compile_definitions(pass-secrets PRIVATE RAPIDJSON_HAS_STDSTRING) 25 | install(TARGETS pass-secrets RUNTIME) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # pass-secrets 2 | CLI Application that provides the Freedesktop Secret Service using Pass as its backend! 3 | 4 | ## Status 5 | Currently working to store secrets with protonmail-bridge. I have not done tests with other applications; if it doesn't work, please open an issue! 6 | 7 | ## How to build 8 | pass-secrets requires pass and sdbus-c++ to be installed on your machine. Rapidjson and nanoid are included in the repo. 9 | 10 | ``` 11 | cd pass-secrets 12 | mkdir build 13 | cd build 14 | cmake .. 15 | make 16 | ``` 17 | 18 | You can then install with `sudo make install` and uninstall with `sudo xargs rm < install_manifest.txt`. This will by default install a systemd user service that can be dbus-activated when enabled. 19 | 20 | ``` 21 | sudo make install 22 | systemctl --user enable pass-secrets 23 | ``` 24 | 25 | Alternatively, you can run it in the background in your bashrc/xinitrc. 26 | ``` 27 | ... 28 | /usr/local/bin/pass-secrets & 29 | ... 30 | ``` 31 | 32 | If you're running pass-secrets on a BSD, or possibly a non-systemd Linux system, you'll need to start a DBus session bus before starting pass-secrets. For instance, your ~/.bash_profile could contain: 33 | 34 | ``` 35 | if ! pgrep -qf -U ${USER:-$(id -u)} dbus.\*--session; then 36 | dbus-daemon --session --fork --address=unix:runtime=yes 2>/dev/null 37 | export DBUS_SESSION_BUS_ADDRESS=unix:path=$XDG_RUNTIME_DIR/bus 38 | fi 39 | ``` 40 | 41 | See [this issue](https://github.com/nullobsi/pass-secrets/issues/11) for more details. 42 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | # Ideas 2 | - use rofi/dmenu to provide prompts for actions 3 | 4 | # TODO 5 | - track sessions and remove when owner disconnects 6 | -------------------------------------------------------------------------------- /adaptors/collectionadaptor.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! 4 | */ 5 | 6 | #ifndef __sdbuscpp__collectionadapter_h__adaptor__H__ 7 | #define __sdbuscpp__collectionadapter_h__adaptor__H__ 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | namespace org { 14 | namespace freedesktop { 15 | namespace Secret { 16 | 17 | class Collection_adaptor 18 | { 19 | public: 20 | static constexpr const char* INTERFACE_NAME = "org.freedesktop.Secret.Collection"; 21 | 22 | protected: 23 | Collection_adaptor(sdbus::IObject& object) 24 | : object_(object) 25 | { 26 | object_.registerMethod("Delete").onInterface(INTERFACE_NAME).withOutputParamNames("prompt").implementedAs([this](){ return this->Delete(); }); 27 | object_.registerMethod("SearchItems").onInterface(INTERFACE_NAME).withInputParamNames("attributes").withOutputParamNames("results").implementedAs([this](const std::map& attributes){ return this->SearchItems(attributes); }); 28 | object_.registerMethod("CreateItem").onInterface(INTERFACE_NAME).withInputParamNames("properties", "secret", "replace").withOutputParamNames("item", "prompt").implementedAs([this](const std::map& properties, const sdbus::Struct, std::vector, std::string>& secret, const bool& replace){ return this->CreateItem(properties, secret, replace); }); 29 | object_.registerSignal("ItemCreated").onInterface(INTERFACE_NAME).withParameters("item"); 30 | object_.registerSignal("ItemDeleted").onInterface(INTERFACE_NAME).withParameters("item"); 31 | object_.registerSignal("ItemChanged").onInterface(INTERFACE_NAME).withParameters("item"); 32 | object_.registerProperty("Items").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Items(); }); 33 | object_.registerProperty("Label").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Label(); }).withSetter([this](const std::string& value){ this->Label(value); }); 34 | object_.registerProperty("Locked").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Locked(); }); 35 | object_.registerProperty("Created").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Created(); }); 36 | object_.registerProperty("Modified").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Modified(); }); 37 | } 38 | 39 | ~Collection_adaptor() = default; 40 | 41 | public: 42 | void emitItemCreated(const sdbus::ObjectPath& item) 43 | { 44 | object_.emitSignal("ItemCreated").onInterface(INTERFACE_NAME).withArguments(item); 45 | } 46 | 47 | void emitItemDeleted(const sdbus::ObjectPath& item) 48 | { 49 | object_.emitSignal("ItemDeleted").onInterface(INTERFACE_NAME).withArguments(item); 50 | } 51 | 52 | void emitItemChanged(const sdbus::ObjectPath& item) 53 | { 54 | object_.emitSignal("ItemChanged").onInterface(INTERFACE_NAME).withArguments(item); 55 | } 56 | 57 | private: 58 | virtual sdbus::ObjectPath Delete() = 0; 59 | virtual std::vector SearchItems(const std::map& attributes) = 0; 60 | virtual std::tuple CreateItem(const std::map& properties, const sdbus::Struct, std::vector, std::string>& secret, const bool& replace) = 0; 61 | 62 | private: 63 | virtual std::vector Items() = 0; 64 | virtual std::string Label() = 0; 65 | virtual void Label(const std::string& value) = 0; 66 | virtual bool Locked() = 0; 67 | virtual uint64_t Created() = 0; 68 | virtual uint64_t Modified() = 0; 69 | 70 | private: 71 | sdbus::IObject& object_; 72 | }; 73 | 74 | }}} // namespaces 75 | 76 | #endif 77 | -------------------------------------------------------------------------------- /adaptors/itemadaptor.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! 4 | */ 5 | 6 | #ifndef __sdbuscpp__itemadapter_h__adaptor__H__ 7 | #define __sdbuscpp__itemadapter_h__adaptor__H__ 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | namespace org { 14 | namespace freedesktop { 15 | namespace Secret { 16 | 17 | class Item_adaptor 18 | { 19 | public: 20 | static constexpr const char* INTERFACE_NAME = "org.freedesktop.Secret.Item"; 21 | 22 | protected: 23 | Item_adaptor(sdbus::IObject& object) 24 | : object_(object) 25 | { 26 | object_.registerMethod("Delete").onInterface(INTERFACE_NAME).withOutputParamNames("Prompt").implementedAs([this](){ return this->Delete(); }); 27 | object_.registerMethod("GetSecret").onInterface(INTERFACE_NAME).withInputParamNames("session").withOutputParamNames("secret").implementedAs([this](const sdbus::ObjectPath& session){ return this->GetSecret(session); }); 28 | object_.registerMethod("SetSecret").onInterface(INTERFACE_NAME).withInputParamNames("secret").implementedAs([this](const sdbus::Struct, std::vector, std::string>& secret){ return this->SetSecret(secret); }); 29 | object_.registerProperty("Locked").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Locked(); }); 30 | object_.registerProperty("Attributes").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Attributes(); }).withSetter([this](const std::map& value){ this->Attributes(value); }); 31 | object_.registerProperty("Label").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Label(); }).withSetter([this](const std::string& value){ this->Label(value); }); 32 | object_.registerProperty("Type").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Type(); }).withSetter([this](const std::string& value){ this->Type(value); }); 33 | object_.registerProperty("Created").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Created(); }); 34 | object_.registerProperty("Modified").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Modified(); }); 35 | } 36 | 37 | ~Item_adaptor() = default; 38 | 39 | private: 40 | virtual sdbus::ObjectPath Delete() = 0; 41 | virtual sdbus::Struct, std::vector, std::string> GetSecret(const sdbus::ObjectPath& session) = 0; 42 | virtual void SetSecret(const sdbus::Struct, std::vector, std::string>& secret) = 0; 43 | 44 | private: 45 | virtual bool Locked() = 0; 46 | virtual std::map Attributes() = 0; 47 | virtual void Attributes(const std::map& value) = 0; 48 | virtual std::string Label() = 0; 49 | virtual void Label(const std::string& value) = 0; 50 | virtual std::string Type() = 0; 51 | virtual void Type(const std::string& value) = 0; 52 | virtual uint64_t Created() = 0; 53 | virtual uint64_t Modified() = 0; 54 | 55 | private: 56 | sdbus::IObject& object_; 57 | }; 58 | 59 | }}} // namespaces 60 | 61 | #endif 62 | -------------------------------------------------------------------------------- /adaptors/promptadaptor.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! 4 | */ 5 | 6 | #ifndef __sdbuscpp__promptadapter_h__adaptor__H__ 7 | #define __sdbuscpp__promptadapter_h__adaptor__H__ 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | namespace org { 14 | namespace freedesktop { 15 | namespace Secret { 16 | 17 | class Prompt_adaptor 18 | { 19 | public: 20 | static constexpr const char* INTERFACE_NAME = "org.freedesktop.Secret.Prompt"; 21 | 22 | protected: 23 | Prompt_adaptor(sdbus::IObject& object) 24 | : object_(object) 25 | { 26 | object_.registerMethod("Prompt").onInterface(INTERFACE_NAME).withInputParamNames("window-id").implementedAs([this](const std::string& window-id){ return this->Prompt(window-id); }); 27 | object_.registerMethod("Dismiss").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->Dismiss(); }); 28 | object_.registerSignal("Completed").onInterface(INTERFACE_NAME).withParameters("dismissed", "result"); 29 | } 30 | 31 | ~Prompt_adaptor() = default; 32 | 33 | public: 34 | void emitCompleted(const bool& dismissed, const sdbus::Variant& result) 35 | { 36 | object_.emitSignal("Completed").onInterface(INTERFACE_NAME).withArguments(dismissed, result); 37 | } 38 | 39 | private: 40 | virtual void Prompt(const std::string& window-id) = 0; 41 | virtual void Dismiss() = 0; 42 | 43 | private: 44 | sdbus::IObject& object_; 45 | }; 46 | 47 | }}} // namespaces 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /adaptors/secretsadaptor.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! 4 | */ 5 | 6 | #ifndef __sdbuscpp__secretsadapter_h__adaptor__H__ 7 | #define __sdbuscpp__secretsadapter_h__adaptor__H__ 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | namespace org { 14 | namespace freedesktop { 15 | namespace Secret { 16 | 17 | class Service_adaptor 18 | { 19 | public: 20 | static constexpr const char* INTERFACE_NAME = "org.freedesktop.Secret.Service"; 21 | 22 | protected: 23 | Service_adaptor(sdbus::IObject& object) 24 | : object_(object) 25 | { 26 | object_.registerMethod("OpenSession").onInterface(INTERFACE_NAME).withInputParamNames("algorithm", "input").withOutputParamNames("output", "result").implementedAs([this](const std::string& algorithm, const sdbus::Variant& input){ return this->OpenSession(algorithm, input); }); 27 | object_.registerMethod("CreateCollection").onInterface(INTERFACE_NAME).withInputParamNames("properties", "alias").withOutputParamNames("collection", "prompt").implementedAs([this](const std::map& properties, const std::string& alias){ return this->CreateCollection(properties, alias); }); 28 | object_.registerMethod("SearchItems").onInterface(INTERFACE_NAME).withInputParamNames("attributes").withOutputParamNames("unlocked", "locked").implementedAs([this](const std::map& attributes){ return this->SearchItems(attributes); }); 29 | object_.registerMethod("Unlock").onInterface(INTERFACE_NAME).withInputParamNames("objects").withOutputParamNames("unlocked", "prompt").implementedAs([this](const std::vector& objects){ return this->Unlock(objects); }); 30 | object_.registerMethod("Lock").onInterface(INTERFACE_NAME).withInputParamNames("objects").withOutputParamNames("locked", "Prompt").implementedAs([this](const std::vector& objects){ return this->Lock(objects); }); 31 | object_.registerMethod("LockService").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->LockService(); }); 32 | object_.registerMethod("ChangeLock").onInterface(INTERFACE_NAME).withInputParamNames("collection").withOutputParamNames("prompt").implementedAs([this](const sdbus::ObjectPath& collection){ return this->ChangeLock(collection); }); 33 | object_.registerMethod("GetSecrets").onInterface(INTERFACE_NAME).withInputParamNames("items", "session").withOutputParamNames("secrets").implementedAs([this](const std::vector& items, const sdbus::ObjectPath& session){ return this->GetSecrets(items, session); }); 34 | object_.registerMethod("ReadAlias").onInterface(INTERFACE_NAME).withInputParamNames("name").withOutputParamNames("collection").implementedAs([this](const std::string& name){ return this->ReadAlias(name); }); 35 | object_.registerMethod("SetAlias").onInterface(INTERFACE_NAME).withInputParamNames("name", "collection").implementedAs([this](const std::string& name, const sdbus::ObjectPath& collection){ return this->SetAlias(name, collection); }); 36 | object_.registerSignal("CollectionCreated").onInterface(INTERFACE_NAME).withParameters("collection"); 37 | object_.registerSignal("CollectionDeleted").onInterface(INTERFACE_NAME).withParameters("collection"); 38 | object_.registerSignal("CollectionChanged").onInterface(INTERFACE_NAME).withParameters("collection"); 39 | object_.registerProperty("Collections").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Collections(); }); 40 | } 41 | 42 | ~Service_adaptor() = default; 43 | 44 | public: 45 | void emitCollectionCreated(const sdbus::ObjectPath& collection) 46 | { 47 | object_.emitSignal("CollectionCreated").onInterface(INTERFACE_NAME).withArguments(collection); 48 | } 49 | 50 | void emitCollectionDeleted(const sdbus::ObjectPath& collection) 51 | { 52 | object_.emitSignal("CollectionDeleted").onInterface(INTERFACE_NAME).withArguments(collection); 53 | } 54 | 55 | void emitCollectionChanged(const sdbus::ObjectPath& collection) 56 | { 57 | object_.emitSignal("CollectionChanged").onInterface(INTERFACE_NAME).withArguments(collection); 58 | } 59 | 60 | private: 61 | virtual std::tuple OpenSession(const std::string& algorithm, const sdbus::Variant& input) = 0; 62 | virtual std::tuple CreateCollection(const std::map& properties, const std::string& alias) = 0; 63 | virtual std::tuple, std::vector> SearchItems(const std::map& attributes) = 0; 64 | virtual std::tuple, sdbus::ObjectPath> Unlock(const std::vector& objects) = 0; 65 | virtual std::tuple, sdbus::ObjectPath> Lock(const std::vector& objects) = 0; 66 | virtual void LockService() = 0; 67 | virtual sdbus::ObjectPath ChangeLock(const sdbus::ObjectPath& collection) = 0; 68 | virtual std::map, std::vector, std::string>> GetSecrets(const std::vector& items, const sdbus::ObjectPath& session) = 0; 69 | virtual sdbus::ObjectPath ReadAlias(const std::string& name) = 0; 70 | virtual void SetAlias(const std::string& name, const sdbus::ObjectPath& collection) = 0; 71 | 72 | private: 73 | virtual std::vector Collections() = 0; 74 | 75 | private: 76 | sdbus::IObject& object_; 77 | }; 78 | 79 | }}} // namespaces 80 | 81 | #endif 82 | -------------------------------------------------------------------------------- /adaptors/sessionadaptor.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! 4 | */ 5 | 6 | #ifndef __sdbuscpp__sessionadapter_h__adaptor__H__ 7 | #define __sdbuscpp__sessionadapter_h__adaptor__H__ 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | namespace org { 14 | namespace freedesktop { 15 | namespace Secret { 16 | 17 | class Session_adaptor 18 | { 19 | public: 20 | static constexpr const char* INTERFACE_NAME = "org.freedesktop.Secret.Session"; 21 | 22 | protected: 23 | Session_adaptor(sdbus::IObject& object) 24 | : object_(object) 25 | { 26 | 27 | } 28 | 29 | ~Session_adaptor() = default; 30 | 31 | 32 | private: 33 | sdbus::IObject& object_; 34 | }; 35 | 36 | }}} // namespaces 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /impl/Collection.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by nullobsi on 2021/03/17. 3 | // 4 | 5 | #include "Collection.h" 6 | #include "SecretService.h" 7 | #include "Item.h" 8 | #include "CollectionProxy.h" 9 | #include 10 | #include 11 | 12 | 13 | Collection::Collection(std::shared_ptr backend_, 14 | sdbus::IConnection &conn, 15 | std::string path, 16 | std::weak_ptr parent_) 17 | : sdbus::AdaptorInterfaces(conn, std::move(path)), 18 | backend(std::move(backend_)), parent(std::move(parent_)) { 19 | registerAdaptor(); 20 | } 21 | 22 | Collection::~Collection() { 23 | unregisterAdaptor(); 24 | } 25 | 26 | sdbus::ObjectPath 27 | Collection::Delete() { 28 | backend->Delete(); 29 | parent.lock()->DiscardCollection(this->backend->getId()); 30 | return sdbus::ObjectPath("/"); 31 | } 32 | 33 | std::vector 34 | Collection::SearchItems(const std::map &attributes) { 35 | auto it = backend->searchItems(attributes); 36 | std::vector r; 37 | r.reserve(it.size()); 38 | for (const auto &id : it) { 39 | r.push_back(items[id]->getPath()); 40 | } 41 | return r; 42 | } 43 | 44 | std::tuple 45 | Collection::CreateItem(const std::map &properties, 46 | const sdbus::Struct, std::vector, std::string> &secret, 47 | const bool &replace) { 48 | auto nAttrib = properties.count("org.freedesktop.Secret.Item.Attributes") && properties.at("org.freedesktop.Secret.Item.Attributes").containsValueOfType>() ? properties.at("org.freedesktop.Secret.Item.Attributes").get>() : std::map(); 49 | auto nLabel = properties.count("org.freedesktop.Secret.Item.Label") && properties.at("org.freedesktop.Secret.Item.Label").containsValueOfType() ? properties.at("org.freedesktop.Secret.Item.Label").get() : "Secret"; 50 | auto nType = properties.count("org.freedesktop.Secret.Item.Type") && properties.at("org.freedesktop.Secret.Item.Type").containsValueOfType() ? properties.at("org.freedesktop.Secret.Item.Type").get() : (nAttrib.count("xdg:schema") ? nAttrib["xdg:schema"] : "org.freedesktop.Secret.Generic"); 51 | auto existing = InternalSearchItems(nAttrib); 52 | if (!existing.empty() && !replace) { 53 | // TODO: this error is not part of spec 54 | throw sdbus::Error("org.freedesktop.Secret.Error.ObjectExists", "Such an object already exists in the store"); 55 | } 56 | auto data = secret.get<2>(); 57 | auto nData = (uint8_t *)malloc(data.size() * sizeof(uint8_t)); 58 | memcpy(nData, data.data(), data.size()*sizeof(uint8_t)); 59 | 60 | if (replace && !existing.empty()) { 61 | auto item = existing[0]->getBackend(); 62 | item->setAttrib(std::move(nAttrib)); 63 | item->setLabel(std::move(nLabel)); 64 | item->setType(std::move(nType)); 65 | item->updateMetadata(); 66 | item->setSecret(nData, data.size()); 67 | ItemCreated(existing[0]->getPath()); 68 | return std::tuple(existing[0]->getPath(), "/"); 69 | } 70 | auto item = this->backend->CreateItem(nData, data.size(), move(nAttrib), move(nLabel), move(nType)); 71 | auto nItem = std::make_shared(item, this->getObject().getConnection(), this->getObjectPath() + "/" + item->getId(), weak_from_this()); 72 | updateItem(nItem); 73 | items.insert({item->getId(), nItem}); 74 | ItemCreated(nItem->getPath()); 75 | return std::tuple(nItem->getPath(), "/"); 76 | } 77 | 78 | std::vector 79 | Collection::Items() { 80 | std::vector r; 81 | auto it = backend->getItems(); 82 | r.reserve(it.size()); 83 | for (const auto &item : it) { 84 | r.push_back(items[item->getId()]->getPath()); 85 | } 86 | return r; 87 | } 88 | 89 | std::string 90 | Collection::Label() { 91 | return backend->getLabel(); 92 | } 93 | 94 | void 95 | Collection::Label(const std::string &value) { 96 | backend->setLabel(value); 97 | backend->updateMetadata(); 98 | } 99 | 100 | bool 101 | Collection::Locked() { 102 | return std::any_of(items.cbegin(), items.cend(), 103 | [](const std::pair> &entry) -> bool { 104 | return entry.second->Locked(); 105 | }); 106 | } 107 | 108 | uint64_t 109 | Collection::Created() { 110 | return backend->getCreated(); 111 | } 112 | 113 | uint64_t 114 | Collection::Modified() { 115 | return 0; 116 | } 117 | 118 | std::shared_ptr 119 | Collection::GetBacking() { 120 | return backend; 121 | } 122 | 123 | std::vector> 124 | Collection::InternalSearchItems(const std::map &attributes) { 125 | auto it = backend->searchItems(attributes); 126 | std::vector> r; 127 | r.reserve(it.size()); 128 | for (const auto &id : it) { 129 | r.push_back(items[id]); 130 | } 131 | return r; 132 | } 133 | 134 | std::map> & 135 | Collection::getItemMap() { 136 | return items; 137 | } 138 | 139 | void 140 | Collection::DiscardObjects() { 141 | while (!discarded.empty()) { 142 | discarded.pop_back(); 143 | } 144 | } 145 | 146 | void 147 | Collection::InitItems() { 148 | for (const auto &item : backend->getItems()) { 149 | items.insert({ 150 | item->getId(), std::make_unique(item, this->getObject().getConnection(), 151 | this->getObjectPath() + "/" + item->getId(), 152 | weak_from_this()) 153 | }); 154 | } 155 | updateAlias(); 156 | } 157 | 158 | 159 | 160 | void 161 | Collection::DiscardItem(std::string id) { 162 | auto ptr = items.extract(id).mapped(); 163 | ItemDeleted(ptr->getPath()); 164 | backend->RemoveItem(ptr->getBackend()->getId()); 165 | discarded.push_back(move(ptr)); 166 | } 167 | 168 | void 169 | Collection::updateAlias() { 170 | std::string path = ""; 171 | if (backend->getAlias().empty()) { 172 | if (proxy) { 173 | proxy.reset(); 174 | } 175 | } else { 176 | path = "/org/freedesktop/secrets/aliases/" + backend->getAlias(); 177 | proxy = std::make_unique(this->getObject().getConnection(), path, weak_from_this()); 178 | } 179 | for (const auto &item : items) { 180 | item.second->updateProxy(path); 181 | } 182 | } 183 | 184 | void 185 | Collection::updateItem(std::shared_ptr item) { 186 | if (!backend->getAlias().empty()) { 187 | auto path = "/org/freedesktop/secrets/aliases/" + backend->getAlias(); 188 | item->updateProxy(path); 189 | } else { 190 | item->updateProxy(""); 191 | } 192 | } 193 | 194 | // TODO: do proxies have to use proxied item path? 195 | void 196 | Collection::ItemCreated(const sdbus::ObjectPath &item) { 197 | emitItemCreated(item); 198 | emitPropertiesChangedSignal("org.freedesktop.Secret.Collection", {"Items"}); 199 | if (proxy) proxy->emitItemCreated(item); 200 | } 201 | 202 | void 203 | Collection::ItemDeleted(const sdbus::ObjectPath &item) { 204 | emitItemDeleted(item); 205 | emitPropertiesChangedSignal("org.freedesktop.Secret.Collection", {"Items"}); 206 | if (proxy) proxy->emitItemDeleted(item); 207 | } 208 | 209 | void 210 | Collection::ItemChanged(const sdbus::ObjectPath &item) { 211 | emitItemChanged(item); 212 | emitPropertiesChangedSignal("org.freedesktop.Secret.Collection", {"Items"}); 213 | if (proxy) proxy->emitItemChanged(item); 214 | } 215 | 216 | std::shared_ptr 217 | Collection::GetService() { 218 | return parent.lock(); 219 | } 220 | -------------------------------------------------------------------------------- /impl/Collection.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by nullobsi on 2021/03/17. 3 | // 4 | 5 | #ifndef PASS_FDO_SECRETS_COLLECTION_H 6 | #define PASS_FDO_SECRETS_COLLECTION_H 7 | 8 | #include "../interop/PassCollection.h" 9 | #include 10 | #include 11 | #include 12 | #include "../adaptors/collectionadaptor.h" 13 | 14 | class SecretService; 15 | class CollectionProxy; 16 | class Item; 17 | 18 | class Collection 19 | : public sdbus::AdaptorInterfaces, 20 | public std::enable_shared_from_this { 21 | public: 22 | Collection(std::shared_ptr backend_, 23 | sdbus::IConnection &conn, 24 | std::string path, 25 | std::weak_ptr parent_); 26 | 27 | ~Collection(); 28 | 29 | void 30 | InitItems(); 31 | 32 | void 33 | DiscardItem(std::string id); 34 | 35 | std::shared_ptr 36 | GetBacking(); 37 | 38 | void 39 | DiscardObjects(); 40 | 41 | std::vector> 42 | InternalSearchItems(const std::map &attributes); 43 | 44 | std::vector 45 | SearchItems(const std::map &attributes) override; 46 | 47 | sdbus::ObjectPath 48 | Delete() override; 49 | 50 | std::tuple 51 | CreateItem(const std::map &properties, 52 | const sdbus::Struct, std::vector, std::string> &secret, 53 | const bool &replace) override; 54 | 55 | std::vector 56 | Items() override; 57 | 58 | std::string 59 | Label() override; 60 | 61 | void 62 | Label(const std::string &value) override; 63 | 64 | bool 65 | Locked() override; 66 | 67 | uint64_t 68 | Created() override; 69 | 70 | uint64_t 71 | Modified() override; 72 | 73 | std::map> & 74 | getItemMap(); 75 | 76 | void 77 | updateAlias(); 78 | 79 | void 80 | updateItem(std::shared_ptr item); 81 | 82 | void 83 | ItemCreated(const sdbus::ObjectPath& item); 84 | 85 | void 86 | ItemDeleted(const sdbus::ObjectPath& item); 87 | 88 | void 89 | ItemChanged(const sdbus::ObjectPath& item); 90 | 91 | std::shared_ptr 92 | GetService(); 93 | 94 | 95 | private: 96 | std::shared_ptr backend; 97 | std::weak_ptr parent; 98 | std::map> items; 99 | std::vector> discarded; 100 | 101 | std::unique_ptr proxy; 102 | }; 103 | 104 | 105 | #endif //PASS_FDO_SECRETS_COLLECTION_H 106 | -------------------------------------------------------------------------------- /impl/CollectionProxy.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by nullobsi on 2021/03/23. 3 | // 4 | 5 | #include "CollectionProxy.h" 6 | #include "Collection.h" 7 | 8 | CollectionProxy::CollectionProxy(sdbus::IConnection &conn, 9 | std::string path, 10 | std::weak_ptr parent_) : sdbus::AdaptorInterfaces(conn, std::move(path)), parent(std::move(parent_)) { 11 | registerAdaptor(); 12 | } 13 | 14 | CollectionProxy::~CollectionProxy() { 15 | unregisterAdaptor(); 16 | } 17 | 18 | sdbus::ObjectPath 19 | CollectionProxy::Delete() { 20 | return parent.lock()->Delete(); 21 | } 22 | 23 | std::vector 24 | CollectionProxy::SearchItems(const std::map &attributes) { 25 | return parent.lock()->SearchItems(attributes); 26 | } 27 | 28 | std::tuple 29 | CollectionProxy::CreateItem(const std::map &properties, 30 | const sdbus::Struct, std::vector, std::string> &secret, 31 | const bool &replace) { 32 | return parent.lock()->CreateItem(properties, secret, replace); 33 | } 34 | 35 | std::vector 36 | CollectionProxy::Items() { 37 | return parent.lock()->Items(); 38 | } 39 | 40 | std::string 41 | CollectionProxy::Label() { 42 | return parent.lock()->Label(); 43 | } 44 | 45 | void 46 | CollectionProxy::Label(const std::string &value) { 47 | parent.lock()->Label(value); 48 | } 49 | 50 | bool 51 | CollectionProxy::Locked() { 52 | return parent.lock()->Locked(); 53 | } 54 | 55 | uint64_t 56 | CollectionProxy::Created() { 57 | return parent.lock()->Created(); 58 | } 59 | 60 | uint64_t 61 | CollectionProxy::Modified() { 62 | return parent.lock()->Modified(); 63 | } 64 | -------------------------------------------------------------------------------- /impl/CollectionProxy.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by nullobsi on 2021/03/23. 3 | // 4 | 5 | #ifndef PASS_SECRETS_COLLECTIONPROXY_H 6 | #define PASS_SECRETS_COLLECTIONPROXY_H 7 | #include "sdbus-c++/sdbus-c++.h" 8 | #include "../adaptors/collectionadaptor.h" 9 | 10 | class Collection; 11 | 12 | class CollectionProxy : public sdbus::AdaptorInterfaces{ 13 | public: 14 | CollectionProxy(sdbus::IConnection &conn, 15 | std::string path, std::weak_ptr parent_); 16 | 17 | ~CollectionProxy(); 18 | 19 | sdbus::ObjectPath Delete() override; 20 | std::vector SearchItems(const std::map& attributes) override; 21 | std::tuple CreateItem(const std::map& properties, const sdbus::Struct, std::vector, std::string>& secret, const bool& replace) override; 22 | std::vector Items() override; 23 | std::string Label() override; 24 | void Label(const std::string& value) override; 25 | bool Locked() override; 26 | uint64_t Created() override; 27 | uint64_t Modified() override; 28 | 29 | private: 30 | std::weak_ptr parent; 31 | }; 32 | 33 | 34 | #endif //PASS_SECRETS_COLLECTIONPROXY_H 35 | -------------------------------------------------------------------------------- /impl/Item.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by nullobsi on 2021/03/22. 3 | // 4 | 5 | // TODO: Proxy item 6 | #include "Item.h" 7 | 8 | #include 9 | #include 10 | #include "Collection.h" 11 | #include "ItemProxy.h" 12 | #include "SecretService.h" 13 | 14 | bool 15 | Item::Locked() { 16 | return !backend->isUnlocked(); 17 | } 18 | 19 | std::map 20 | Item::Attributes() { 21 | return backend->getAttrib(); 22 | } 23 | 24 | void 25 | Item::Attributes(const std::map &value) { 26 | backend->setAttrib(value); 27 | backend->updateMetadata(); 28 | emitPropertiesChangedSignal("org.freedesktop.Secret.Item", {"Attributes", "Modified"}); 29 | parent.lock()->ItemChanged(getPath()); 30 | } 31 | 32 | std::string 33 | Item::Label() { 34 | return backend->getLabel(); 35 | } 36 | 37 | void 38 | Item::Label(const std::string &value) { 39 | backend->setLabel(value); 40 | backend->updateMetadata(); 41 | emitPropertiesChangedSignal("org.freedesktop.Secret.Item", {"Label", "Modified"}); 42 | parent.lock()->ItemChanged(getPath()); 43 | } 44 | 45 | std::string 46 | Item::Type() { 47 | return backend->getType(); 48 | } 49 | 50 | void 51 | Item::Type(const std::string &value) { 52 | backend->setType(value); 53 | backend->updateMetadata(); 54 | emitPropertiesChangedSignal("org.freedesktop.Secret.Item", {"Type", "Modified"}); 55 | parent.lock()->ItemChanged(getPath()); 56 | } 57 | 58 | uint64_t 59 | Item::Created() { 60 | return backend->getCreated(); 61 | } 62 | 63 | uint64_t 64 | Item::Modified() { 65 | return backend->getModified(); 66 | } 67 | 68 | sdbus::ObjectPath 69 | Item::Delete() { 70 | backend->Delete(); 71 | parent.lock()->DiscardItem(this->backend->getId()); 72 | return sdbus::ObjectPath("/"); 73 | } 74 | 75 | Item::Item(std::shared_ptr backend_, 76 | sdbus::IConnection &conn, 77 | std::string path, 78 | std::weak_ptr parent_) : backend(std::move(backend_)), 79 | sdbus::AdaptorInterfaces( 80 | conn, std::move(path)), parent(std::move(parent_)) { 81 | registerAdaptor(); 82 | } 83 | 84 | Item::~Item() { 85 | unregisterAdaptor(); 86 | } 87 | 88 | sdbus::Struct, std::vector, std::string> 89 | Item::GetSecret(const sdbus::ObjectPath &session) { 90 | if (!backend->isUnlocked()) { 91 | throw sdbus::Error("org.freedesktop.Secret.Error.IsLocked", 92 | "The object must be unlocked before this action can be carried out."); 93 | } 94 | auto encrypted = parent.lock()->GetService() 95 | ->EncryptSecret(session, backend->getSecret(), backend->getSecretLength()); 96 | 97 | 98 | // TODO: how to check item type? 99 | return std::tuple(session, std::move(encrypted.first), std::move(encrypted.second), "text/plain"); 100 | } 101 | 102 | sdbus::ObjectPath 103 | Item::getPath() { 104 | return sdbus::ObjectPath(getObject().getObjectPath()); 105 | } 106 | 107 | void 108 | Item::SetSecret(const sdbus::Struct, std::vector, std::string> &secret) { 109 | auto data = secret.get<2>(); 110 | auto nData = (uint8_t *)malloc(sizeof(uint8_t) * data.size()); 111 | memcpy(nData, data.data(), sizeof(uint8_t) * data.size()); 112 | backend->setSecret(nData, data.size()); 113 | emitPropertiesChangedSignal("org.freedesktop.Secret.Item", {"Locked", "Modified"}); 114 | 115 | parent.lock()->ItemChanged(getPath()); 116 | } 117 | 118 | std::shared_ptr 119 | Item::getBackend() { 120 | return backend; 121 | } 122 | 123 | void 124 | Item::updateProxy(std::string proxiedCollection) { 125 | if (proxiedCollection.empty()) { 126 | if (proxy) { 127 | proxy.reset(); 128 | } 129 | } else { 130 | proxy = std::make_unique(this->getObject().getConnection(), 131 | proxiedCollection + "/" + backend->getId(), weak_from_this()); 132 | } 133 | } 134 | 135 | std::string 136 | Item::getCollectionId() { 137 | return parent.lock()->GetBacking()->getId(); 138 | } 139 | -------------------------------------------------------------------------------- /impl/Item.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by nullobsi on 2021/03/22. 3 | // 4 | 5 | #ifndef PASS_FDO_SECRETS_ITEM_H 6 | #define PASS_FDO_SECRETS_ITEM_H 7 | 8 | #include "../interop/PassItem.h" 9 | #include "sdbus-c++/sdbus-c++.h" 10 | #include "sdbus-c++/StandardInterfaces.h" 11 | #include "../adaptors/itemadaptor.h" 12 | 13 | class Collection; 14 | class ItemProxy; 15 | 16 | class Item : public sdbus::AdaptorInterfaces , public std::enable_shared_from_this { 17 | public: 18 | Item(std::shared_ptr backend_, 19 | sdbus::IConnection &conn, 20 | std::string path, 21 | std::weak_ptr parent_); 22 | 23 | ~Item(); 24 | 25 | sdbus::ObjectPath 26 | getPath(); 27 | 28 | sdbus::ObjectPath 29 | Delete() override; 30 | 31 | sdbus::Struct, std::vector, std::string> 32 | GetSecret(const sdbus::ObjectPath &session) override; 33 | 34 | void 35 | SetSecret(const sdbus::Struct, std::vector, std::string> &secret) override; 36 | 37 | bool 38 | Locked() override; 39 | 40 | std::map 41 | Attributes() override; 42 | 43 | void 44 | Attributes(const std::map &value) override; 45 | 46 | std::string 47 | Label() override; 48 | 49 | void 50 | Label(const std::string &value) override; 51 | 52 | std::string 53 | Type() override; 54 | 55 | void 56 | Type(const std::string &value) override; 57 | 58 | uint64_t 59 | Created() override; 60 | 61 | uint64_t 62 | Modified() override; 63 | 64 | std::shared_ptr 65 | getBackend(); 66 | 67 | void 68 | updateProxy(std::string proxiedCollection); 69 | 70 | std::string 71 | getCollectionId(); 72 | 73 | 74 | private: 75 | std::shared_ptr backend; 76 | std::weak_ptr parent; 77 | 78 | std::unique_ptr proxy; 79 | }; 80 | 81 | 82 | #endif //PASS_FDO_SECRETS_ITEM_H 83 | -------------------------------------------------------------------------------- /impl/ItemProxy.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by nullobsi on 2021/03/23. 3 | // 4 | 5 | #include "ItemProxy.h" 6 | #include "Item.h" 7 | 8 | ItemProxy::ItemProxy(sdbus::IConnection &conn, 9 | std::string path, 10 | std::weak_ptr parent_): parent(std::move(parent_)), sdbus::AdaptorInterfaces(conn, std::move(path)) { 11 | registerAdaptor(); 12 | } 13 | 14 | ItemProxy::~ItemProxy() { 15 | unregisterAdaptor(); 16 | } 17 | 18 | sdbus::ObjectPath 19 | ItemProxy::Delete() { 20 | return parent.lock()->Delete(); 21 | } 22 | 23 | sdbus::Struct, std::vector, std::string> 24 | ItemProxy::GetSecret(const sdbus::ObjectPath &session) { 25 | return parent.lock()->GetSecret(session); 26 | } 27 | 28 | void 29 | ItemProxy::SetSecret(const sdbus::Struct, std::vector, std::string> &secret) { 30 | return parent.lock()->SetSecret(secret); 31 | } 32 | 33 | bool 34 | ItemProxy::Locked() { 35 | return parent.lock()->Locked(); 36 | } 37 | 38 | std::map 39 | ItemProxy::Attributes() { 40 | return parent.lock()->Attributes(); 41 | } 42 | 43 | void 44 | ItemProxy::Attributes(const std::map &value) { 45 | return parent.lock()->Attributes(value); 46 | } 47 | 48 | std::string 49 | ItemProxy::Label() { 50 | return parent.lock()->Label(); 51 | } 52 | 53 | void 54 | ItemProxy::Label(const std::string &value) { 55 | return parent.lock()->Label(value); 56 | } 57 | 58 | std::string 59 | ItemProxy::Type() { 60 | return parent.lock()->Type(); 61 | } 62 | 63 | void 64 | ItemProxy::Type(const std::string &value) { 65 | return parent.lock()->Type(value); 66 | } 67 | 68 | uint64_t 69 | ItemProxy::Created() { 70 | return parent.lock()->Created(); 71 | } 72 | 73 | uint64_t 74 | ItemProxy::Modified() { 75 | return parent.lock()->Modified(); 76 | } 77 | -------------------------------------------------------------------------------- /impl/ItemProxy.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by nullobsi on 2021/03/23. 3 | // 4 | 5 | #ifndef PASS_SECRETS_ITEMPROXY_H 6 | #define PASS_SECRETS_ITEMPROXY_H 7 | 8 | #include 9 | #include 10 | #include "../adaptors/itemadaptor.h" 11 | 12 | class Item; 13 | 14 | class ItemProxy : public sdbus::AdaptorInterfaces { 15 | public: 16 | ItemProxy(sdbus::IConnection &conn, 17 | std::string path, std::weak_ptr parent_); 18 | 19 | ~ItemProxy(); 20 | 21 | sdbus::ObjectPath Delete() override; 22 | sdbus::Struct, std::vector, std::string> GetSecret(const sdbus::ObjectPath& session) override; 23 | void SetSecret(const sdbus::Struct, std::vector, std::string>& secret) override; 24 | bool Locked() override; 25 | std::map Attributes() override; 26 | void Attributes(const std::map& value) override; 27 | std::string Label() override; 28 | void Label(const std::string& value) override; 29 | std::string Type() override; 30 | void Type(const std::string& value) override; 31 | uint64_t Created() override; 32 | uint64_t Modified() override; 33 | 34 | private: 35 | std::weak_ptr parent; 36 | }; 37 | 38 | 39 | #endif //PASS_SECRETS_ITEMPROXY_H 40 | -------------------------------------------------------------------------------- /impl/SecretService.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by nullobsi on 2021/03/17. 3 | // 4 | 5 | #include "SecretService.h" 6 | #include "Session.h" 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "Item.h" 12 | #include "sessions/sessions.h" 13 | 14 | using namespace std; 15 | 16 | SecretService::SecretService(sdbus::IConnection &conn, 17 | std::string path) : AdaptorInterfaces(conn, std::move(path)) { 18 | 19 | registerAdaptor(); 20 | } 21 | 22 | SecretService::~SecretService() { 23 | unregisterAdaptor(); 24 | } 25 | 26 | std::tuple 27 | SecretService::OpenSession(const std::string &algorithm, 28 | const sdbus::Variant &input) { 29 | unique_ptr session; 30 | auto ptr = weak_from_this(); 31 | auto &conn = this->getObject().getConnection(); 32 | auto path = "/org/freedesktop/secrets/session/" + nanoid::generate(); 33 | sdbus::Variant rtn; 34 | if (algorithm.empty() || algorithm == "plain") { 35 | session = make_unique(ptr, conn, path); 36 | rtn = session->getOutput(); 37 | } else { 38 | throw sdbus::Error("org.freedesktop.DBus.Error.NotSupported", "Only plain is supported"); 39 | } 40 | 41 | sessions.insert({path, move(session)}); 42 | 43 | return {rtn, path}; 44 | } 45 | 46 | std::tuple 47 | SecretService::CreateCollection(const std::map &properties, 48 | const std::string &alias) { 49 | auto nLabel = properties.count("org.freedesktop.Secret.Collection.Label") && properties.at("org.freedesktop.Secret.Collection.Label").containsValueOfType() ? properties.at("org.freedesktop.Secret.Collection.Label").get() : "Collection"; 50 | auto nCollection = store.CreateCollection(nLabel, alias); 51 | auto coll = make_shared(nCollection, this->getObject().getConnection(), "/org/freedesktop/secrets/collection/" + nCollection->getId(), weak_from_this()); 52 | collections.insert({nCollection->getId(), coll}); 53 | return std::tuple(coll->getObjectPath(), "/"); 54 | } 55 | 56 | std::tuple, std::vector> 57 | SecretService::SearchItems(const std::map &attributes) { 58 | vector locked; 59 | vector unlocked; 60 | for (const auto &collection : collections) { 61 | vector> items = collection.second->InternalSearchItems(attributes); 62 | for (const auto &item : items) { 63 | if (item->Locked()) { 64 | locked.push_back(item->getPath()); 65 | } else { 66 | unlocked.push_back(item->getPath()); 67 | } 68 | } 69 | } 70 | return std::tuple(unlocked, locked); 71 | } 72 | 73 | 74 | std::tuple, sdbus::ObjectPath> 75 | SecretService::Unlock(const std::vector &objects) { 76 | // TODO: Prompt? 77 | std::vector unlocked; 78 | for (const auto &item : fromObjectPath((const vector &)objects)) { 79 | if (!item->Locked() || item->getBackend()->unlock()) { 80 | item->emitPropertiesChangedSignal("org.freedesktop.Secret.Item", {"Locked"}); 81 | collections[item->getCollectionId()]->emitPropertiesChangedSignal("org.freedesktop.Secret.Collection", {"Locked"}); 82 | unlocked.push_back(item->getPath()); 83 | } 84 | } 85 | 86 | return std::tuple(unlocked, "/"); 87 | } 88 | 89 | std::tuple, sdbus::ObjectPath> 90 | SecretService::Lock(const std::vector &objects) { 91 | // TODO: Prompt? 92 | std::vector locked; 93 | for (const auto &item : fromObjectPath((const vector &)objects)) { 94 | // TODO: could this cause a segfault? 95 | item->getBackend()->lock(); 96 | item->emitPropertiesChangedSignal("org.freedesktop.Secret.Item", {"Locked"}); 97 | collections[item->getCollectionId()]->emitPropertiesChangedSignal("org.freedesktop.Secret.Collection", {"Locked"}); 98 | locked.push_back(item->getPath()); 99 | } 100 | return std::tuple(locked, "/"); 101 | } 102 | 103 | void 104 | SecretService::LockService() { 105 | for (const auto &entry : collections) { 106 | for (const auto &item : entry.second->GetBacking()->getItems()) { 107 | item->lock(); 108 | } 109 | } 110 | } 111 | 112 | sdbus::ObjectPath 113 | SecretService::ChangeLock(const sdbus::ObjectPath &collection) { 114 | // TODO: Change lock 115 | // this isn't mentioned in the specification (gnome keyring specific?) 116 | return sdbus::ObjectPath("/"); 117 | } 118 | 119 | std::map, std::vector, std::string>> 120 | SecretService::GetSecrets(const std::vector &items, 121 | const sdbus::ObjectPath &session) { 122 | auto it = fromObjectPath((const vector &)items); 123 | std::map, std::vector, std::string>> retn; 124 | for (const auto &item : it) { 125 | auto res = item->GetSecret(session); 126 | retn.insert({item->getPath(), res}); 127 | } 128 | return retn; 129 | } 130 | 131 | sdbus::ObjectPath 132 | SecretService::ReadAlias(const std::string &name) { 133 | for (auto &entry : collections) { 134 | auto alias = entry.second->GetBacking()->getAlias(); 135 | if (alias == name) { 136 | return sdbus::ObjectPath(entry.second->getObjectPath()); 137 | } 138 | } 139 | return sdbus::ObjectPath("/"); 140 | } 141 | 142 | void 143 | SecretService::SetAlias(const std::string &name, 144 | const sdbus::ObjectPath &collection) { 145 | std::filesystem::path objPath((string)collection); 146 | auto collId = objPath.filename().generic_string(); 147 | if (!collections.count(collId)) { 148 | throw sdbus::Error("org.freedesktop.Secret.Error.NoSuchObject", "No such item or collection exists."); 149 | } 150 | collections[collId]->GetBacking()->setAlias(name); 151 | collections[collId]->GetBacking()->updateMetadata(); 152 | collections[collId]->updateAlias(); 153 | } 154 | 155 | std::vector 156 | SecretService::Collections() { 157 | std::vector cs; 158 | cs.reserve(collections.size()); 159 | 160 | for (auto &entry : collections) { 161 | cs.emplace_back(entry.second->getObjectPath()); 162 | } 163 | 164 | return cs; 165 | } 166 | 167 | std::vector> 168 | SecretService::fromObjectPath(const std::vector &paths) { 169 | std::vector> items; 170 | for (const auto &objectPath : paths) { 171 | auto oPath = std::filesystem::path((string)objectPath); 172 | if (oPath.has_parent_path()) { 173 | if (oPath.parent_path().filename() == "collection") { // Find all items 174 | auto collId = oPath.filename().generic_string(); 175 | if (collections.count(collId)) { 176 | for (const auto &item : collections[collId]->getItemMap()) { 177 | items.push_back(item.second); 178 | } 179 | } 180 | } else { // this should be a normal item 181 | // obtain ids from path 182 | auto itemId = oPath.filename().generic_string(); 183 | auto collId = oPath.parent_path().filename().generic_string(); 184 | // if exists 185 | if (collections.count(collId) && collections[collId]->getItemMap().count(itemId)) { 186 | auto item = collections[collId]->getItemMap()[itemId]; 187 | items.push_back(item); 188 | } 189 | } 190 | } 191 | } 192 | return items; 193 | } 194 | 195 | void 196 | SecretService::DiscardSession(const std::string &path) { 197 | discardedSessions.push_back(move(sessions.extract(path).mapped())); 198 | } 199 | 200 | void 201 | SecretService::DiscardCollection(std::string id) { 202 | discardedCollections.push_back(move(collections.extract(id).mapped())); 203 | } 204 | 205 | void 206 | SecretService::DiscardObjects() { 207 | while (!discardedSessions.empty()) { 208 | discardedSessions.pop_back(); 209 | } 210 | while (!discardedCollections.empty()) { 211 | discardedCollections.pop_back(); 212 | } 213 | for (const auto &entry : collections) { 214 | entry.second->DiscardObjects(); 215 | } 216 | } 217 | 218 | void 219 | SecretService::InitCollections() { 220 | for (auto c : store.GetCollections()) { 221 | auto id = c->getId(); 222 | auto collection = make_shared(c, this->getObject().getConnection(), 223 | "/org/freedesktop/secrets/collection/" + id, this->weak_from_this()); 224 | collection->InitItems(); 225 | collections.insert({id, move(collection)}); 226 | } 227 | } 228 | 229 | std::pair, std::vector> 230 | SecretService::EncryptSecret(const string &path, uint8_t *data, size_t len) { 231 | if (!sessions.at(path)) throw std::runtime_error("Error: Session does not exist!"); 232 | return std::move(sessions[path]->encryptSecret(data, len)); 233 | } 234 | 235 | 236 | -------------------------------------------------------------------------------- /impl/SecretService.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by nullobsi on 2021/03/17. 3 | // 4 | 5 | #ifndef PASS_FDO_SECRETS_SECRETSERVICE_H 6 | #define PASS_FDO_SECRETS_SECRETSERVICE_H 7 | 8 | #include 9 | #include "../adaptors/secretsadaptor.h" 10 | #include "../interop/PassStore.h" 11 | #include "Collection.h" 12 | 13 | class Session; 14 | 15 | class SecretService 16 | : public sdbus::AdaptorInterfaces, 17 | public std::enable_shared_from_this { 18 | public: 19 | SecretService(sdbus::IConnection &conn, 20 | std::string path); 21 | 22 | ~SecretService(); 23 | 24 | void 25 | DiscardObjects(); 26 | 27 | void 28 | DiscardSession(const std::string &path); 29 | 30 | void 31 | DiscardCollection(std::string id); 32 | 33 | void 34 | InitCollections(); 35 | 36 | std::pair, std::vector> 37 | EncryptSecret(const std::string &path, uint8_t *data, size_t len); 38 | 39 | protected: 40 | std::tuple 41 | OpenSession(const std::string &algorithm, 42 | const sdbus::Variant &input) override; 43 | 44 | std::tuple 45 | CreateCollection(const std::map &properties, 46 | const std::string &alias) override; 47 | 48 | std::tuple, std::vector> 49 | SearchItems(const std::map &attributes) override; 50 | 51 | std::tuple, sdbus::ObjectPath> 52 | Unlock(const std::vector &objects) override; 53 | 54 | std::tuple, sdbus::ObjectPath> 55 | Lock(const std::vector &objects) override; 56 | 57 | void 58 | LockService() override; 59 | 60 | sdbus::ObjectPath 61 | ChangeLock(const sdbus::ObjectPath &collection) override; 62 | 63 | std::map, std::vector, std::string>> 64 | GetSecrets(const std::vector &items, 65 | const sdbus::ObjectPath &session) override; 66 | 67 | sdbus::ObjectPath 68 | ReadAlias(const std::string &name) override; 69 | 70 | void 71 | SetAlias(const std::string &name, 72 | const sdbus::ObjectPath &collection) override; 73 | 74 | std::vector 75 | Collections() override; 76 | 77 | private: 78 | std::map> sessions; 79 | std::vector> discardedSessions; 80 | 81 | PassStore store; 82 | std::map> collections; 83 | std::vector> discardedCollections; 84 | 85 | std::vector> 86 | fromObjectPath(const std::vector &paths); 87 | }; 88 | 89 | #endif //PASS_FDO_SECRETS_SECRETSERVICE_H 90 | -------------------------------------------------------------------------------- /impl/Session.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by nullobsi on 2021/03/17. 3 | // 4 | 5 | #include "Session.h" 6 | #include "SecretService.h" 7 | 8 | #include 9 | 10 | 11 | Session::Session(std::weak_ptr parent_, 12 | sdbus::IConnection &conn, 13 | std::string path) : AdaptorInterfaces(conn, std::move(path)), parent(std::move(parent_)) { 14 | sdbus::Flags flags; 15 | flags.set(sdbus::Flags::METHOD_NO_REPLY); 16 | this->getObject() 17 | .registerMethod(INTERFACE_NAME, "Close", "", "", [this](sdbus::MethodCall call) -> void { this->Close(call); }, 18 | flags); 19 | registerAdaptor(); 20 | } 21 | 22 | void 23 | Session::Close(sdbus::MethodCall msg) { 24 | parent.lock()->DiscardSession(this->getObjectPath()); 25 | } 26 | 27 | Session::~Session() { 28 | this->unregisterAdaptor(); 29 | }; 30 | -------------------------------------------------------------------------------- /impl/Session.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by nullobsi on 2021/03/17. 3 | // 4 | 5 | #ifndef PASS_FDO_SECRETS_SESSION_H 6 | #define PASS_FDO_SECRETS_SESSION_H 7 | 8 | #include "../adaptors/sessionadaptor.h" 9 | 10 | class SecretService; 11 | 12 | class Session : public sdbus::AdaptorInterfaces { 13 | public: 14 | 15 | Session(std::weak_ptr parent, 16 | sdbus::IConnection &conn, 17 | std::string path); 18 | 19 | ~Session(); 20 | 21 | virtual std::pair, std::vector> encryptSecret(uint8_t *secret, size_t len) = 0; 22 | virtual sdbus::Variant getOutput() = 0; 23 | 24 | private: 25 | void 26 | Close(sdbus::MethodCall msg); 27 | 28 | std::weak_ptr parent; 29 | }; 30 | 31 | 32 | #endif //PASS_FDO_SECRETS_SESSION_H 33 | -------------------------------------------------------------------------------- /impl/sessions/Plain.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by nullobsi on 2021/03/26. 3 | // 4 | 5 | #include "Plain.h" 6 | 7 | #include 8 | namespace Sessions { 9 | Plain::Plain(std::weak_ptr parent_, 10 | sdbus::IConnection &conn, 11 | std::string path) : Session(std::move(parent_), conn, std::move(path)) { 12 | 13 | } 14 | 15 | std::pair, std::vector> 16 | Plain::encryptSecret(uint8_t *secret, 17 | size_t len) { 18 | return std::pair(std::vector(), std::vector(secret, secret + len)); 19 | } 20 | 21 | sdbus::Variant 22 | Plain::getOutput() { 23 | return sdbus::Variant(""); 24 | } 25 | } -------------------------------------------------------------------------------- /impl/sessions/Plain.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by nullobsi on 2021/03/26. 3 | // 4 | 5 | #ifndef PASS_SECRETS_PLAIN_H 6 | #define PASS_SECRETS_PLAIN_H 7 | #include "../Session.h" 8 | 9 | namespace Sessions { 10 | class Plain : public Session { 11 | public: 12 | Plain(std::weak_ptr parent_, 13 | sdbus::IConnection &conn, 14 | std::string path); 15 | 16 | std::pair, std::vector> 17 | encryptSecret(uint8_t *secret, 18 | size_t len) override; 19 | 20 | sdbus::Variant getOutput() override; 21 | }; 22 | } 23 | 24 | #endif //PASS_SECRETS_PLAIN_H 25 | -------------------------------------------------------------------------------- /impl/sessions/sessions.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by nullobsi on 2021/03/26. 3 | // 4 | 5 | #ifndef PASS_SECRETS_SESSIONS_H 6 | #define PASS_SECRETS_SESSIONS_H 7 | #include "Plain.h" 8 | #endif //PASS_SECRETS_SESSIONS_H 9 | -------------------------------------------------------------------------------- /include/nanoid/crypto_random.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "nanoid/settings.h" 4 | #include 5 | #include 6 | #include 7 | 8 | namespace NANOID_NAMESPACE { 9 | class crypto_random_base { 10 | public: 11 | virtual void 12 | next_bytes(std::uint8_t *buffer, 13 | std::size_t size); //Cannot be pure virtual due to std::async semantics 14 | virtual ~crypto_random_base() {} 15 | }; 16 | 17 | template 18 | class crypto_random : public crypto_random_base { 19 | private: 20 | _UniformRandomBitGenerator _generator; 21 | public: 22 | using result_type = std::uint32_t; 23 | 24 | crypto_random & 25 | operator=(const crypto_random &other) = delete; 26 | 27 | crypto_random(const crypto_random &) = delete; 28 | 29 | crypto_random() : _generator() {} 30 | 31 | template 32 | crypto_random(_Args... args) : _generator(std::forward<_Args>(args)...) {} 33 | 34 | static constexpr result_type 35 | (min)() { 36 | return _UniformRandomBitGenerator::min(); 37 | } 38 | 39 | static constexpr result_type 40 | (max)() { 41 | return _UniformRandomBitGenerator::max(); 42 | } 43 | 44 | result_type 45 | operator()() { 46 | return _generator(); 47 | } 48 | 49 | void 50 | next_bytes(std::uint8_t *buffer, 51 | std::size_t size) override { 52 | std::size_t reps = (size / sizeof(result_type)) * sizeof(result_type); 53 | std::size_t i = 0; 54 | for (; i < reps; i += sizeof(result_type)) { 55 | *(result_type *)(buffer + i) = operator()(); 56 | } 57 | if (i == size) return; 58 | result_type last = operator()(); 59 | for (; i < size; ++i) { 60 | *(buffer + i) = (std::uint8_t)((last >> (8 * (i - reps)))); 61 | } 62 | } 63 | }; 64 | } -------------------------------------------------------------------------------- /include/nanoid/nanoid.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "nanoid/settings.h" 4 | #include "nanoid/crypto_random.h" 5 | #include 6 | #include 7 | #include 8 | 9 | namespace NANOID_NAMESPACE { 10 | std::string 11 | generate(); 12 | 13 | std::string 14 | generate(const std::string &alphabet); 15 | 16 | std::string 17 | generate(std::size_t size); 18 | 19 | std::string 20 | generate(const std::string &alphabet, 21 | std::size_t size); 22 | 23 | std::future 24 | generate_async(); 25 | 26 | std::future 27 | generate_async(const std::string &alphabet); 28 | 29 | std::future 30 | generate_async(std::size_t size); 31 | 32 | std::future 33 | generate_async(const std::string &alphabet, 34 | std::size_t size); 35 | 36 | std::string 37 | generate(crypto_random_base &random); 38 | 39 | std::string 40 | generate(crypto_random_base &random, 41 | const std::string &alphabet); 42 | 43 | std::string 44 | generate(crypto_random_base &random, 45 | std::size_t size); 46 | 47 | std::string 48 | generate(crypto_random_base &random, 49 | const std::string &alphabet, 50 | std::size_t size); 51 | 52 | namespace impl { 53 | int 54 | clz32(int x); 55 | } 56 | } -------------------------------------------------------------------------------- /include/nanoid/settings.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef NANOID_NAMESPACE 4 | #define NANOID_NAMESPACE nanoid 5 | #endif 6 | -------------------------------------------------------------------------------- /include/rapidjson/cursorstreamwrapper.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_CURSORSTREAMWRAPPER_H_ 16 | #define RAPIDJSON_CURSORSTREAMWRAPPER_H_ 17 | 18 | #include "stream.h" 19 | 20 | #if defined(__GNUC__) 21 | RAPIDJSON_DIAG_PUSH 22 | RAPIDJSON_DIAG_OFF(effc++) 23 | #endif 24 | 25 | #if defined(_MSC_VER) && _MSC_VER <= 1800 26 | RAPIDJSON_DIAG_PUSH 27 | RAPIDJSON_DIAG_OFF(4702) // unreachable code 28 | RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated 29 | #endif 30 | 31 | RAPIDJSON_NAMESPACE_BEGIN 32 | 33 | 34 | //! Cursor stream wrapper for counting line and column number if error exists. 35 | /*! 36 | \tparam InputStream Any stream that implements Stream Concept 37 | */ 38 | template > 39 | class CursorStreamWrapper : public GenericStreamWrapper { 40 | public: 41 | typedef typename Encoding::Ch Ch; 42 | 43 | CursorStreamWrapper(InputStream& is): 44 | GenericStreamWrapper(is), line_(1), col_(0) {} 45 | 46 | // counting line and column number 47 | Ch Take() { 48 | Ch ch = this->is_.Take(); 49 | if(ch == '\n') { 50 | line_ ++; 51 | col_ = 0; 52 | } else { 53 | col_ ++; 54 | } 55 | return ch; 56 | } 57 | 58 | //! Get the error line number, if error exists. 59 | size_t GetLine() const { return line_; } 60 | //! Get the error column number, if error exists. 61 | size_t GetColumn() const { return col_; } 62 | 63 | private: 64 | size_t line_; //!< Current Line 65 | size_t col_; //!< Current Column 66 | }; 67 | 68 | #if defined(_MSC_VER) && _MSC_VER <= 1800 69 | RAPIDJSON_DIAG_POP 70 | #endif 71 | 72 | #if defined(__GNUC__) 73 | RAPIDJSON_DIAG_POP 74 | #endif 75 | 76 | RAPIDJSON_NAMESPACE_END 77 | 78 | #endif // RAPIDJSON_CURSORSTREAMWRAPPER_H_ 79 | -------------------------------------------------------------------------------- /include/rapidjson/error/en.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_ERROR_EN_H_ 16 | #define RAPIDJSON_ERROR_EN_H_ 17 | 18 | #include "error.h" 19 | 20 | #ifdef __clang__ 21 | RAPIDJSON_DIAG_PUSH 22 | RAPIDJSON_DIAG_OFF(switch-enum) 23 | RAPIDJSON_DIAG_OFF(covered-switch-default) 24 | #endif 25 | 26 | RAPIDJSON_NAMESPACE_BEGIN 27 | 28 | //! Maps error code of parsing into error message. 29 | /*! 30 | \ingroup RAPIDJSON_ERRORS 31 | \param parseErrorCode Error code obtained in parsing. 32 | \return the error message. 33 | \note User can make a copy of this function for localization. 34 | Using switch-case is safer for future modification of error codes. 35 | */ 36 | inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErrorCode) { 37 | switch (parseErrorCode) { 38 | case kParseErrorNone: return RAPIDJSON_ERROR_STRING("No error."); 39 | 40 | case kParseErrorDocumentEmpty: return RAPIDJSON_ERROR_STRING("The document is empty."); 41 | case kParseErrorDocumentRootNotSingular: return RAPIDJSON_ERROR_STRING("The document root must not be followed by other values."); 42 | 43 | case kParseErrorValueInvalid: return RAPIDJSON_ERROR_STRING("Invalid value."); 44 | 45 | case kParseErrorObjectMissName: return RAPIDJSON_ERROR_STRING("Missing a name for object member."); 46 | case kParseErrorObjectMissColon: return RAPIDJSON_ERROR_STRING("Missing a colon after a name of object member."); 47 | case kParseErrorObjectMissCommaOrCurlyBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or '}' after an object member."); 48 | 49 | case kParseErrorArrayMissCommaOrSquareBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or ']' after an array element."); 50 | 51 | case kParseErrorStringUnicodeEscapeInvalidHex: return RAPIDJSON_ERROR_STRING("Incorrect hex digit after \\u escape in string."); 52 | case kParseErrorStringUnicodeSurrogateInvalid: return RAPIDJSON_ERROR_STRING("The surrogate pair in string is invalid."); 53 | case kParseErrorStringEscapeInvalid: return RAPIDJSON_ERROR_STRING("Invalid escape character in string."); 54 | case kParseErrorStringMissQuotationMark: return RAPIDJSON_ERROR_STRING("Missing a closing quotation mark in string."); 55 | case kParseErrorStringInvalidEncoding: return RAPIDJSON_ERROR_STRING("Invalid encoding in string."); 56 | 57 | case kParseErrorNumberTooBig: return RAPIDJSON_ERROR_STRING("Number too big to be stored in double."); 58 | case kParseErrorNumberMissFraction: return RAPIDJSON_ERROR_STRING("Miss fraction part in number."); 59 | case kParseErrorNumberMissExponent: return RAPIDJSON_ERROR_STRING("Miss exponent in number."); 60 | 61 | case kParseErrorTermination: return RAPIDJSON_ERROR_STRING("Terminate parsing due to Handler error."); 62 | case kParseErrorUnspecificSyntaxError: return RAPIDJSON_ERROR_STRING("Unspecific syntax error."); 63 | 64 | default: return RAPIDJSON_ERROR_STRING("Unknown error."); 65 | } 66 | } 67 | 68 | //! Maps error code of validation into error message. 69 | /*! 70 | \ingroup RAPIDJSON_ERRORS 71 | \param validateErrorCode Error code obtained from validator. 72 | \return the error message. 73 | \note User can make a copy of this function for localization. 74 | Using switch-case is safer for future modification of error codes. 75 | */ 76 | inline const RAPIDJSON_ERROR_CHARTYPE* GetValidateError_En(ValidateErrorCode validateErrorCode) { 77 | switch (validateErrorCode) { 78 | case kValidateErrors: return RAPIDJSON_ERROR_STRING("One or more validation errors have occurred"); 79 | case kValidateErrorNone: return RAPIDJSON_ERROR_STRING("No error."); 80 | 81 | case kValidateErrorMultipleOf: return RAPIDJSON_ERROR_STRING("Number '%actual' is not a multiple of the 'multipleOf' value '%expected'."); 82 | case kValidateErrorMaximum: return RAPIDJSON_ERROR_STRING("Number '%actual' is greater than the 'maximum' value '%expected'."); 83 | case kValidateErrorExclusiveMaximum: return RAPIDJSON_ERROR_STRING("Number '%actual' is greater than or equal to the 'exclusiveMaximum' value '%expected'."); 84 | case kValidateErrorMinimum: return RAPIDJSON_ERROR_STRING("Number '%actual' is less than the 'minimum' value '%expected'."); 85 | case kValidateErrorExclusiveMinimum: return RAPIDJSON_ERROR_STRING("Number '%actual' is less than or equal to the 'exclusiveMinimum' value '%expected'."); 86 | 87 | case kValidateErrorMaxLength: return RAPIDJSON_ERROR_STRING("String '%actual' is longer than the 'maxLength' value '%expected'."); 88 | case kValidateErrorMinLength: return RAPIDJSON_ERROR_STRING("String '%actual' is shorter than the 'minLength' value '%expected'."); 89 | case kValidateErrorPattern: return RAPIDJSON_ERROR_STRING("String '%actual' does not match the 'pattern' regular expression."); 90 | 91 | case kValidateErrorMaxItems: return RAPIDJSON_ERROR_STRING("Array of length '%actual' is longer than the 'maxItems' value '%expected'."); 92 | case kValidateErrorMinItems: return RAPIDJSON_ERROR_STRING("Array of length '%actual' is shorter than the 'minItems' value '%expected'."); 93 | case kValidateErrorUniqueItems: return RAPIDJSON_ERROR_STRING("Array has duplicate items at indices '%duplicates' but 'uniqueItems' is true."); 94 | case kValidateErrorAdditionalItems: return RAPIDJSON_ERROR_STRING("Array has an additional item at index '%disallowed' that is not allowed by the schema."); 95 | 96 | case kValidateErrorMaxProperties: return RAPIDJSON_ERROR_STRING("Object has '%actual' members which is more than 'maxProperties' value '%expected'."); 97 | case kValidateErrorMinProperties: return RAPIDJSON_ERROR_STRING("Object has '%actual' members which is less than 'minProperties' value '%expected'."); 98 | case kValidateErrorRequired: return RAPIDJSON_ERROR_STRING("Object is missing the following members required by the schema: '%missing'."); 99 | case kValidateErrorAdditionalProperties: return RAPIDJSON_ERROR_STRING("Object has an additional member '%disallowed' that is not allowed by the schema."); 100 | case kValidateErrorPatternProperties: return RAPIDJSON_ERROR_STRING("Object has 'patternProperties' that are not allowed by the schema."); 101 | case kValidateErrorDependencies: return RAPIDJSON_ERROR_STRING("Object has missing property or schema dependencies, refer to following errors."); 102 | 103 | case kValidateErrorEnum: return RAPIDJSON_ERROR_STRING("Property has a value that is not one of its allowed enumerated values."); 104 | case kValidateErrorType: return RAPIDJSON_ERROR_STRING("Property has a type '%actual' that is not in the following list: '%expected'."); 105 | 106 | case kValidateErrorOneOf: return RAPIDJSON_ERROR_STRING("Property did not match any of the sub-schemas specified by 'oneOf', refer to following errors."); 107 | case kValidateErrorOneOfMatch: return RAPIDJSON_ERROR_STRING("Property matched more than one of the sub-schemas specified by 'oneOf'."); 108 | case kValidateErrorAllOf: return RAPIDJSON_ERROR_STRING("Property did not match all of the sub-schemas specified by 'allOf', refer to following errors."); 109 | case kValidateErrorAnyOf: return RAPIDJSON_ERROR_STRING("Property did not match any of the sub-schemas specified by 'anyOf', refer to following errors."); 110 | case kValidateErrorNot: return RAPIDJSON_ERROR_STRING("Property matched the sub-schema specified by 'not'."); 111 | 112 | default: return RAPIDJSON_ERROR_STRING("Unknown error."); 113 | } 114 | } 115 | 116 | RAPIDJSON_NAMESPACE_END 117 | 118 | #ifdef __clang__ 119 | RAPIDJSON_DIAG_POP 120 | #endif 121 | 122 | #endif // RAPIDJSON_ERROR_EN_H_ 123 | -------------------------------------------------------------------------------- /include/rapidjson/filereadstream.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_FILEREADSTREAM_H_ 16 | #define RAPIDJSON_FILEREADSTREAM_H_ 17 | 18 | #include "stream.h" 19 | #include 20 | 21 | #ifdef __clang__ 22 | RAPIDJSON_DIAG_PUSH 23 | RAPIDJSON_DIAG_OFF(padded) 24 | RAPIDJSON_DIAG_OFF(unreachable-code) 25 | RAPIDJSON_DIAG_OFF(missing-noreturn) 26 | #endif 27 | 28 | RAPIDJSON_NAMESPACE_BEGIN 29 | 30 | //! File byte stream for input using fread(). 31 | /*! 32 | \note implements Stream concept 33 | */ 34 | class FileReadStream { 35 | public: 36 | typedef char Ch; //!< Character type (byte). 37 | 38 | //! Constructor. 39 | /*! 40 | \param fp File pointer opened for read. 41 | \param buffer user-supplied buffer. 42 | \param bufferSize size of buffer in bytes. Must >=4 bytes. 43 | */ 44 | FileReadStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) { 45 | RAPIDJSON_ASSERT(fp_ != 0); 46 | RAPIDJSON_ASSERT(bufferSize >= 4); 47 | Read(); 48 | } 49 | 50 | Ch Peek() const { return *current_; } 51 | Ch Take() { Ch c = *current_; Read(); return c; } 52 | size_t Tell() const { return count_ + static_cast(current_ - buffer_); } 53 | 54 | // Not implemented 55 | void Put(Ch) { RAPIDJSON_ASSERT(false); } 56 | void Flush() { RAPIDJSON_ASSERT(false); } 57 | Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } 58 | size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } 59 | 60 | // For encoding detection only. 61 | const Ch* Peek4() const { 62 | return (current_ + 4 - !eof_ <= bufferLast_) ? current_ : 0; 63 | } 64 | 65 | private: 66 | void Read() { 67 | if (current_ < bufferLast_) 68 | ++current_; 69 | else if (!eof_) { 70 | count_ += readCount_; 71 | readCount_ = std::fread(buffer_, 1, bufferSize_, fp_); 72 | bufferLast_ = buffer_ + readCount_ - 1; 73 | current_ = buffer_; 74 | 75 | if (readCount_ < bufferSize_) { 76 | buffer_[readCount_] = '\0'; 77 | ++bufferLast_; 78 | eof_ = true; 79 | } 80 | } 81 | } 82 | 83 | std::FILE* fp_; 84 | Ch *buffer_; 85 | size_t bufferSize_; 86 | Ch *bufferLast_; 87 | Ch *current_; 88 | size_t readCount_; 89 | size_t count_; //!< Number of characters read 90 | bool eof_; 91 | }; 92 | 93 | RAPIDJSON_NAMESPACE_END 94 | 95 | #ifdef __clang__ 96 | RAPIDJSON_DIAG_POP 97 | #endif 98 | 99 | #endif // RAPIDJSON_FILESTREAM_H_ 100 | -------------------------------------------------------------------------------- /include/rapidjson/filewritestream.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_FILEWRITESTREAM_H_ 16 | #define RAPIDJSON_FILEWRITESTREAM_H_ 17 | 18 | #include "stream.h" 19 | #include 20 | 21 | #ifdef __clang__ 22 | RAPIDJSON_DIAG_PUSH 23 | RAPIDJSON_DIAG_OFF(unreachable-code) 24 | #endif 25 | 26 | RAPIDJSON_NAMESPACE_BEGIN 27 | 28 | //! Wrapper of C file stream for output using fwrite(). 29 | /*! 30 | \note implements Stream concept 31 | */ 32 | class FileWriteStream { 33 | public: 34 | typedef char Ch; //!< Character type. Only support char. 35 | 36 | FileWriteStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferEnd_(buffer + bufferSize), current_(buffer_) { 37 | RAPIDJSON_ASSERT(fp_ != 0); 38 | } 39 | 40 | void Put(char c) { 41 | if (current_ >= bufferEnd_) 42 | Flush(); 43 | 44 | *current_++ = c; 45 | } 46 | 47 | void PutN(char c, size_t n) { 48 | size_t avail = static_cast(bufferEnd_ - current_); 49 | while (n > avail) { 50 | std::memset(current_, c, avail); 51 | current_ += avail; 52 | Flush(); 53 | n -= avail; 54 | avail = static_cast(bufferEnd_ - current_); 55 | } 56 | 57 | if (n > 0) { 58 | std::memset(current_, c, n); 59 | current_ += n; 60 | } 61 | } 62 | 63 | void Flush() { 64 | if (current_ != buffer_) { 65 | size_t result = std::fwrite(buffer_, 1, static_cast(current_ - buffer_), fp_); 66 | if (result < static_cast(current_ - buffer_)) { 67 | // failure deliberately ignored at this time 68 | // added to avoid warn_unused_result build errors 69 | } 70 | current_ = buffer_; 71 | } 72 | } 73 | 74 | // Not implemented 75 | char Peek() const { RAPIDJSON_ASSERT(false); return 0; } 76 | char Take() { RAPIDJSON_ASSERT(false); return 0; } 77 | size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } 78 | char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } 79 | size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; } 80 | 81 | private: 82 | // Prohibit copy constructor & assignment operator. 83 | FileWriteStream(const FileWriteStream&); 84 | FileWriteStream& operator=(const FileWriteStream&); 85 | 86 | std::FILE* fp_; 87 | char *buffer_; 88 | char *bufferEnd_; 89 | char *current_; 90 | }; 91 | 92 | //! Implement specialized version of PutN() with memset() for better performance. 93 | template<> 94 | inline void PutN(FileWriteStream& stream, char c, size_t n) { 95 | stream.PutN(c, n); 96 | } 97 | 98 | RAPIDJSON_NAMESPACE_END 99 | 100 | #ifdef __clang__ 101 | RAPIDJSON_DIAG_POP 102 | #endif 103 | 104 | #endif // RAPIDJSON_FILESTREAM_H_ 105 | -------------------------------------------------------------------------------- /include/rapidjson/fwd.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_FWD_H_ 16 | #define RAPIDJSON_FWD_H_ 17 | 18 | #include "rapidjson.h" 19 | 20 | RAPIDJSON_NAMESPACE_BEGIN 21 | 22 | // encodings.h 23 | 24 | template struct UTF8; 25 | template struct UTF16; 26 | template struct UTF16BE; 27 | template struct UTF16LE; 28 | template struct UTF32; 29 | template struct UTF32BE; 30 | template struct UTF32LE; 31 | template struct ASCII; 32 | template struct AutoUTF; 33 | 34 | template 35 | struct Transcoder; 36 | 37 | // allocators.h 38 | 39 | class CrtAllocator; 40 | 41 | template 42 | class MemoryPoolAllocator; 43 | 44 | // stream.h 45 | 46 | template 47 | struct GenericStringStream; 48 | 49 | typedef GenericStringStream > StringStream; 50 | 51 | template 52 | struct GenericInsituStringStream; 53 | 54 | typedef GenericInsituStringStream > InsituStringStream; 55 | 56 | // stringbuffer.h 57 | 58 | template 59 | class GenericStringBuffer; 60 | 61 | typedef GenericStringBuffer, CrtAllocator> StringBuffer; 62 | 63 | // filereadstream.h 64 | 65 | class FileReadStream; 66 | 67 | // filewritestream.h 68 | 69 | class FileWriteStream; 70 | 71 | // memorybuffer.h 72 | 73 | template 74 | struct GenericMemoryBuffer; 75 | 76 | typedef GenericMemoryBuffer MemoryBuffer; 77 | 78 | // memorystream.h 79 | 80 | struct MemoryStream; 81 | 82 | // reader.h 83 | 84 | template 85 | struct BaseReaderHandler; 86 | 87 | template 88 | class GenericReader; 89 | 90 | typedef GenericReader, UTF8, CrtAllocator> Reader; 91 | 92 | // writer.h 93 | 94 | template 95 | class Writer; 96 | 97 | // prettywriter.h 98 | 99 | template 100 | class PrettyWriter; 101 | 102 | // document.h 103 | 104 | template 105 | class GenericMember; 106 | 107 | template 108 | class GenericMemberIterator; 109 | 110 | template 111 | struct GenericStringRef; 112 | 113 | template 114 | class GenericValue; 115 | 116 | typedef GenericValue, MemoryPoolAllocator > Value; 117 | 118 | template 119 | class GenericDocument; 120 | 121 | typedef GenericDocument, MemoryPoolAllocator, CrtAllocator> Document; 122 | 123 | // pointer.h 124 | 125 | template 126 | class GenericPointer; 127 | 128 | typedef GenericPointer Pointer; 129 | 130 | // schema.h 131 | 132 | template 133 | class IGenericRemoteSchemaDocumentProvider; 134 | 135 | template 136 | class GenericSchemaDocument; 137 | 138 | typedef GenericSchemaDocument SchemaDocument; 139 | typedef IGenericRemoteSchemaDocumentProvider IRemoteSchemaDocumentProvider; 140 | 141 | template < 142 | typename SchemaDocumentType, 143 | typename OutputHandler, 144 | typename StateAllocator> 145 | class GenericSchemaValidator; 146 | 147 | typedef GenericSchemaValidator, void>, CrtAllocator> SchemaValidator; 148 | 149 | RAPIDJSON_NAMESPACE_END 150 | 151 | #endif // RAPIDJSON_RAPIDJSONFWD_H_ 152 | -------------------------------------------------------------------------------- /include/rapidjson/internal/clzll.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_CLZLL_H_ 16 | #define RAPIDJSON_CLZLL_H_ 17 | 18 | #include "../rapidjson.h" 19 | 20 | #if defined(_MSC_VER) && !defined(UNDER_CE) 21 | #include 22 | #if defined(_WIN64) 23 | #pragma intrinsic(_BitScanReverse64) 24 | #else 25 | #pragma intrinsic(_BitScanReverse) 26 | #endif 27 | #endif 28 | 29 | RAPIDJSON_NAMESPACE_BEGIN 30 | namespace internal { 31 | 32 | inline uint32_t clzll(uint64_t x) { 33 | // Passing 0 to __builtin_clzll is UB in GCC and results in an 34 | // infinite loop in the software implementation. 35 | RAPIDJSON_ASSERT(x != 0); 36 | 37 | #if defined(_MSC_VER) && !defined(UNDER_CE) 38 | unsigned long r = 0; 39 | #if defined(_WIN64) 40 | _BitScanReverse64(&r, x); 41 | #else 42 | // Scan the high 32 bits. 43 | if (_BitScanReverse(&r, static_cast(x >> 32))) 44 | return 63 - (r + 32); 45 | 46 | // Scan the low 32 bits. 47 | _BitScanReverse(&r, static_cast(x & 0xFFFFFFFF)); 48 | #endif // _WIN64 49 | 50 | return 63 - r; 51 | #elif (defined(__GNUC__) && __GNUC__ >= 4) || RAPIDJSON_HAS_BUILTIN(__builtin_clzll) 52 | // __builtin_clzll wrapper 53 | return static_cast(__builtin_clzll(x)); 54 | #else 55 | // naive version 56 | uint32_t r = 0; 57 | while (!(x & (static_cast(1) << 63))) { 58 | x <<= 1; 59 | ++r; 60 | } 61 | 62 | return r; 63 | #endif // _MSC_VER 64 | } 65 | 66 | #define RAPIDJSON_CLZLL RAPIDJSON_NAMESPACE::internal::clzll 67 | 68 | } // namespace internal 69 | RAPIDJSON_NAMESPACE_END 70 | 71 | #endif // RAPIDJSON_CLZLL_H_ 72 | -------------------------------------------------------------------------------- /include/rapidjson/internal/dtoa.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | // This is a C++ header-only implementation of Grisu2 algorithm from the publication: 16 | // Loitsch, Florian. "Printing floating-point numbers quickly and accurately with 17 | // integers." ACM Sigplan Notices 45.6 (2010): 233-243. 18 | 19 | #ifndef RAPIDJSON_DTOA_ 20 | #define RAPIDJSON_DTOA_ 21 | 22 | #include "itoa.h" // GetDigitsLut() 23 | #include "diyfp.h" 24 | #include "ieee754.h" 25 | 26 | RAPIDJSON_NAMESPACE_BEGIN 27 | namespace internal { 28 | 29 | #ifdef __GNUC__ 30 | RAPIDJSON_DIAG_PUSH 31 | RAPIDJSON_DIAG_OFF(effc++) 32 | RAPIDJSON_DIAG_OFF(array-bounds) // some gcc versions generate wrong warnings https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59124 33 | #endif 34 | 35 | inline void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uint64_t ten_kappa, uint64_t wp_w) { 36 | while (rest < wp_w && delta - rest >= ten_kappa && 37 | (rest + ten_kappa < wp_w || /// closer 38 | wp_w - rest > rest + ten_kappa - wp_w)) { 39 | buffer[len - 1]--; 40 | rest += ten_kappa; 41 | } 42 | } 43 | 44 | inline int CountDecimalDigit32(uint32_t n) { 45 | // Simple pure C++ implementation was faster than __builtin_clz version in this situation. 46 | if (n < 10) return 1; 47 | if (n < 100) return 2; 48 | if (n < 1000) return 3; 49 | if (n < 10000) return 4; 50 | if (n < 100000) return 5; 51 | if (n < 1000000) return 6; 52 | if (n < 10000000) return 7; 53 | if (n < 100000000) return 8; 54 | // Will not reach 10 digits in DigitGen() 55 | //if (n < 1000000000) return 9; 56 | //return 10; 57 | return 9; 58 | } 59 | 60 | inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buffer, int* len, int* K) { 61 | static const uint32_t kPow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 }; 62 | const DiyFp one(uint64_t(1) << -Mp.e, Mp.e); 63 | const DiyFp wp_w = Mp - W; 64 | uint32_t p1 = static_cast(Mp.f >> -one.e); 65 | uint64_t p2 = Mp.f & (one.f - 1); 66 | int kappa = CountDecimalDigit32(p1); // kappa in [0, 9] 67 | *len = 0; 68 | 69 | while (kappa > 0) { 70 | uint32_t d = 0; 71 | switch (kappa) { 72 | case 9: d = p1 / 100000000; p1 %= 100000000; break; 73 | case 8: d = p1 / 10000000; p1 %= 10000000; break; 74 | case 7: d = p1 / 1000000; p1 %= 1000000; break; 75 | case 6: d = p1 / 100000; p1 %= 100000; break; 76 | case 5: d = p1 / 10000; p1 %= 10000; break; 77 | case 4: d = p1 / 1000; p1 %= 1000; break; 78 | case 3: d = p1 / 100; p1 %= 100; break; 79 | case 2: d = p1 / 10; p1 %= 10; break; 80 | case 1: d = p1; p1 = 0; break; 81 | default:; 82 | } 83 | if (d || *len) 84 | buffer[(*len)++] = static_cast('0' + static_cast(d)); 85 | kappa--; 86 | uint64_t tmp = (static_cast(p1) << -one.e) + p2; 87 | if (tmp <= delta) { 88 | *K += kappa; 89 | GrisuRound(buffer, *len, delta, tmp, static_cast(kPow10[kappa]) << -one.e, wp_w.f); 90 | return; 91 | } 92 | } 93 | 94 | // kappa = 0 95 | for (;;) { 96 | p2 *= 10; 97 | delta *= 10; 98 | char d = static_cast(p2 >> -one.e); 99 | if (d || *len) 100 | buffer[(*len)++] = static_cast('0' + d); 101 | p2 &= one.f - 1; 102 | kappa--; 103 | if (p2 < delta) { 104 | *K += kappa; 105 | int index = -kappa; 106 | GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * (index < 9 ? kPow10[index] : 0)); 107 | return; 108 | } 109 | } 110 | } 111 | 112 | inline void Grisu2(double value, char* buffer, int* length, int* K) { 113 | const DiyFp v(value); 114 | DiyFp w_m, w_p; 115 | v.NormalizedBoundaries(&w_m, &w_p); 116 | 117 | const DiyFp c_mk = GetCachedPower(w_p.e, K); 118 | const DiyFp W = v.Normalize() * c_mk; 119 | DiyFp Wp = w_p * c_mk; 120 | DiyFp Wm = w_m * c_mk; 121 | Wm.f++; 122 | Wp.f--; 123 | DigitGen(W, Wp, Wp.f - Wm.f, buffer, length, K); 124 | } 125 | 126 | inline char* WriteExponent(int K, char* buffer) { 127 | if (K < 0) { 128 | *buffer++ = '-'; 129 | K = -K; 130 | } 131 | 132 | if (K >= 100) { 133 | *buffer++ = static_cast('0' + static_cast(K / 100)); 134 | K %= 100; 135 | const char* d = GetDigitsLut() + K * 2; 136 | *buffer++ = d[0]; 137 | *buffer++ = d[1]; 138 | } 139 | else if (K >= 10) { 140 | const char* d = GetDigitsLut() + K * 2; 141 | *buffer++ = d[0]; 142 | *buffer++ = d[1]; 143 | } 144 | else 145 | *buffer++ = static_cast('0' + static_cast(K)); 146 | 147 | return buffer; 148 | } 149 | 150 | inline char* Prettify(char* buffer, int length, int k, int maxDecimalPlaces) { 151 | const int kk = length + k; // 10^(kk-1) <= v < 10^kk 152 | 153 | if (0 <= k && kk <= 21) { 154 | // 1234e7 -> 12340000000 155 | for (int i = length; i < kk; i++) 156 | buffer[i] = '0'; 157 | buffer[kk] = '.'; 158 | buffer[kk + 1] = '0'; 159 | return &buffer[kk + 2]; 160 | } 161 | else if (0 < kk && kk <= 21) { 162 | // 1234e-2 -> 12.34 163 | std::memmove(&buffer[kk + 1], &buffer[kk], static_cast(length - kk)); 164 | buffer[kk] = '.'; 165 | if (0 > k + maxDecimalPlaces) { 166 | // When maxDecimalPlaces = 2, 1.2345 -> 1.23, 1.102 -> 1.1 167 | // Remove extra trailing zeros (at least one) after truncation. 168 | for (int i = kk + maxDecimalPlaces; i > kk + 1; i--) 169 | if (buffer[i] != '0') 170 | return &buffer[i + 1]; 171 | return &buffer[kk + 2]; // Reserve one zero 172 | } 173 | else 174 | return &buffer[length + 1]; 175 | } 176 | else if (-6 < kk && kk <= 0) { 177 | // 1234e-6 -> 0.001234 178 | const int offset = 2 - kk; 179 | std::memmove(&buffer[offset], &buffer[0], static_cast(length)); 180 | buffer[0] = '0'; 181 | buffer[1] = '.'; 182 | for (int i = 2; i < offset; i++) 183 | buffer[i] = '0'; 184 | if (length - kk > maxDecimalPlaces) { 185 | // When maxDecimalPlaces = 2, 0.123 -> 0.12, 0.102 -> 0.1 186 | // Remove extra trailing zeros (at least one) after truncation. 187 | for (int i = maxDecimalPlaces + 1; i > 2; i--) 188 | if (buffer[i] != '0') 189 | return &buffer[i + 1]; 190 | return &buffer[3]; // Reserve one zero 191 | } 192 | else 193 | return &buffer[length + offset]; 194 | } 195 | else if (kk < -maxDecimalPlaces) { 196 | // Truncate to zero 197 | buffer[0] = '0'; 198 | buffer[1] = '.'; 199 | buffer[2] = '0'; 200 | return &buffer[3]; 201 | } 202 | else if (length == 1) { 203 | // 1e30 204 | buffer[1] = 'e'; 205 | return WriteExponent(kk - 1, &buffer[2]); 206 | } 207 | else { 208 | // 1234e30 -> 1.234e33 209 | std::memmove(&buffer[2], &buffer[1], static_cast(length - 1)); 210 | buffer[1] = '.'; 211 | buffer[length + 1] = 'e'; 212 | return WriteExponent(kk - 1, &buffer[0 + length + 2]); 213 | } 214 | } 215 | 216 | inline char* dtoa(double value, char* buffer, int maxDecimalPlaces = 324) { 217 | RAPIDJSON_ASSERT(maxDecimalPlaces >= 1); 218 | Double d(value); 219 | if (d.IsZero()) { 220 | if (d.Sign()) 221 | *buffer++ = '-'; // -0.0, Issue #289 222 | buffer[0] = '0'; 223 | buffer[1] = '.'; 224 | buffer[2] = '0'; 225 | return &buffer[3]; 226 | } 227 | else { 228 | if (value < 0) { 229 | *buffer++ = '-'; 230 | value = -value; 231 | } 232 | int length, K; 233 | Grisu2(value, buffer, &length, &K); 234 | return Prettify(buffer, length, K, maxDecimalPlaces); 235 | } 236 | } 237 | 238 | #ifdef __GNUC__ 239 | RAPIDJSON_DIAG_POP 240 | #endif 241 | 242 | } // namespace internal 243 | RAPIDJSON_NAMESPACE_END 244 | 245 | #endif // RAPIDJSON_DTOA_ 246 | -------------------------------------------------------------------------------- /include/rapidjson/internal/ieee754.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_IEEE754_ 16 | #define RAPIDJSON_IEEE754_ 17 | 18 | #include "../rapidjson.h" 19 | 20 | RAPIDJSON_NAMESPACE_BEGIN 21 | namespace internal { 22 | 23 | class Double { 24 | public: 25 | Double() {} 26 | Double(double d) : d_(d) {} 27 | Double(uint64_t u) : u_(u) {} 28 | 29 | double Value() const { return d_; } 30 | uint64_t Uint64Value() const { return u_; } 31 | 32 | double NextPositiveDouble() const { 33 | RAPIDJSON_ASSERT(!Sign()); 34 | return Double(u_ + 1).Value(); 35 | } 36 | 37 | bool Sign() const { return (u_ & kSignMask) != 0; } 38 | uint64_t Significand() const { return u_ & kSignificandMask; } 39 | int Exponent() const { return static_cast(((u_ & kExponentMask) >> kSignificandSize) - kExponentBias); } 40 | 41 | bool IsNan() const { return (u_ & kExponentMask) == kExponentMask && Significand() != 0; } 42 | bool IsInf() const { return (u_ & kExponentMask) == kExponentMask && Significand() == 0; } 43 | bool IsNanOrInf() const { return (u_ & kExponentMask) == kExponentMask; } 44 | bool IsNormal() const { return (u_ & kExponentMask) != 0 || Significand() == 0; } 45 | bool IsZero() const { return (u_ & (kExponentMask | kSignificandMask)) == 0; } 46 | 47 | uint64_t IntegerSignificand() const { return IsNormal() ? Significand() | kHiddenBit : Significand(); } 48 | int IntegerExponent() const { return (IsNormal() ? Exponent() : kDenormalExponent) - kSignificandSize; } 49 | uint64_t ToBias() const { return (u_ & kSignMask) ? ~u_ + 1 : u_ | kSignMask; } 50 | 51 | static int EffectiveSignificandSize(int order) { 52 | if (order >= -1021) 53 | return 53; 54 | else if (order <= -1074) 55 | return 0; 56 | else 57 | return order + 1074; 58 | } 59 | 60 | private: 61 | static const int kSignificandSize = 52; 62 | static const int kExponentBias = 0x3FF; 63 | static const int kDenormalExponent = 1 - kExponentBias; 64 | static const uint64_t kSignMask = RAPIDJSON_UINT64_C2(0x80000000, 0x00000000); 65 | static const uint64_t kExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000); 66 | static const uint64_t kSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF); 67 | static const uint64_t kHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000); 68 | 69 | union { 70 | double d_; 71 | uint64_t u_; 72 | }; 73 | }; 74 | 75 | } // namespace internal 76 | RAPIDJSON_NAMESPACE_END 77 | 78 | #endif // RAPIDJSON_IEEE754_ 79 | -------------------------------------------------------------------------------- /include/rapidjson/internal/meta.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_INTERNAL_META_H_ 16 | #define RAPIDJSON_INTERNAL_META_H_ 17 | 18 | #include "../rapidjson.h" 19 | 20 | #ifdef __GNUC__ 21 | RAPIDJSON_DIAG_PUSH 22 | RAPIDJSON_DIAG_OFF(effc++) 23 | #endif 24 | 25 | #if defined(_MSC_VER) && !defined(__clang__) 26 | RAPIDJSON_DIAG_PUSH 27 | RAPIDJSON_DIAG_OFF(6334) 28 | #endif 29 | 30 | #if RAPIDJSON_HAS_CXX11_TYPETRAITS 31 | #include 32 | #endif 33 | 34 | //@cond RAPIDJSON_INTERNAL 35 | RAPIDJSON_NAMESPACE_BEGIN 36 | namespace internal { 37 | 38 | // Helper to wrap/convert arbitrary types to void, useful for arbitrary type matching 39 | template struct Void { typedef void Type; }; 40 | 41 | /////////////////////////////////////////////////////////////////////////////// 42 | // BoolType, TrueType, FalseType 43 | // 44 | template struct BoolType { 45 | static const bool Value = Cond; 46 | typedef BoolType Type; 47 | }; 48 | typedef BoolType TrueType; 49 | typedef BoolType FalseType; 50 | 51 | 52 | /////////////////////////////////////////////////////////////////////////////// 53 | // SelectIf, BoolExpr, NotExpr, AndExpr, OrExpr 54 | // 55 | 56 | template struct SelectIfImpl { template struct Apply { typedef T1 Type; }; }; 57 | template <> struct SelectIfImpl { template struct Apply { typedef T2 Type; }; }; 58 | template struct SelectIfCond : SelectIfImpl::template Apply {}; 59 | template struct SelectIf : SelectIfCond {}; 60 | 61 | template struct AndExprCond : FalseType {}; 62 | template <> struct AndExprCond : TrueType {}; 63 | template struct OrExprCond : TrueType {}; 64 | template <> struct OrExprCond : FalseType {}; 65 | 66 | template struct BoolExpr : SelectIf::Type {}; 67 | template struct NotExpr : SelectIf::Type {}; 68 | template struct AndExpr : AndExprCond::Type {}; 69 | template struct OrExpr : OrExprCond::Type {}; 70 | 71 | 72 | /////////////////////////////////////////////////////////////////////////////// 73 | // AddConst, MaybeAddConst, RemoveConst 74 | template struct AddConst { typedef const T Type; }; 75 | template struct MaybeAddConst : SelectIfCond {}; 76 | template struct RemoveConst { typedef T Type; }; 77 | template struct RemoveConst { typedef T Type; }; 78 | 79 | 80 | /////////////////////////////////////////////////////////////////////////////// 81 | // IsSame, IsConst, IsMoreConst, IsPointer 82 | // 83 | template struct IsSame : FalseType {}; 84 | template struct IsSame : TrueType {}; 85 | 86 | template struct IsConst : FalseType {}; 87 | template struct IsConst : TrueType {}; 88 | 89 | template 90 | struct IsMoreConst 91 | : AndExpr::Type, typename RemoveConst::Type>, 92 | BoolType::Value >= IsConst::Value> >::Type {}; 93 | 94 | template struct IsPointer : FalseType {}; 95 | template struct IsPointer : TrueType {}; 96 | 97 | /////////////////////////////////////////////////////////////////////////////// 98 | // IsBaseOf 99 | // 100 | #if RAPIDJSON_HAS_CXX11_TYPETRAITS 101 | 102 | template struct IsBaseOf 103 | : BoolType< ::std::is_base_of::value> {}; 104 | 105 | #else // simplified version adopted from Boost 106 | 107 | template struct IsBaseOfImpl { 108 | RAPIDJSON_STATIC_ASSERT(sizeof(B) != 0); 109 | RAPIDJSON_STATIC_ASSERT(sizeof(D) != 0); 110 | 111 | typedef char (&Yes)[1]; 112 | typedef char (&No) [2]; 113 | 114 | template 115 | static Yes Check(const D*, T); 116 | static No Check(const B*, int); 117 | 118 | struct Host { 119 | operator const B*() const; 120 | operator const D*(); 121 | }; 122 | 123 | enum { Value = (sizeof(Check(Host(), 0)) == sizeof(Yes)) }; 124 | }; 125 | 126 | template struct IsBaseOf 127 | : OrExpr, BoolExpr > >::Type {}; 128 | 129 | #endif // RAPIDJSON_HAS_CXX11_TYPETRAITS 130 | 131 | 132 | ////////////////////////////////////////////////////////////////////////// 133 | // EnableIf / DisableIf 134 | // 135 | template struct EnableIfCond { typedef T Type; }; 136 | template struct EnableIfCond { /* empty */ }; 137 | 138 | template struct DisableIfCond { typedef T Type; }; 139 | template struct DisableIfCond { /* empty */ }; 140 | 141 | template 142 | struct EnableIf : EnableIfCond {}; 143 | 144 | template 145 | struct DisableIf : DisableIfCond {}; 146 | 147 | // SFINAE helpers 148 | struct SfinaeTag {}; 149 | template struct RemoveSfinaeTag; 150 | template struct RemoveSfinaeTag { typedef T Type; }; 151 | 152 | #define RAPIDJSON_REMOVEFPTR_(type) \ 153 | typename ::RAPIDJSON_NAMESPACE::internal::RemoveSfinaeTag \ 154 | < ::RAPIDJSON_NAMESPACE::internal::SfinaeTag&(*) type>::Type 155 | 156 | #define RAPIDJSON_ENABLEIF(cond) \ 157 | typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \ 158 | ::Type * = NULL 159 | 160 | #define RAPIDJSON_DISABLEIF(cond) \ 161 | typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \ 162 | ::Type * = NULL 163 | 164 | #define RAPIDJSON_ENABLEIF_RETURN(cond,returntype) \ 165 | typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \ 166 | ::Type 168 | 169 | #define RAPIDJSON_DISABLEIF_RETURN(cond,returntype) \ 170 | typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \ 171 | ::Type 173 | 174 | } // namespace internal 175 | RAPIDJSON_NAMESPACE_END 176 | //@endcond 177 | 178 | #if defined(_MSC_VER) && !defined(__clang__) 179 | RAPIDJSON_DIAG_POP 180 | #endif 181 | 182 | #ifdef __GNUC__ 183 | RAPIDJSON_DIAG_POP 184 | #endif 185 | 186 | #endif // RAPIDJSON_INTERNAL_META_H_ 187 | -------------------------------------------------------------------------------- /include/rapidjson/internal/pow10.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_POW10_ 16 | #define RAPIDJSON_POW10_ 17 | 18 | #include "../rapidjson.h" 19 | 20 | RAPIDJSON_NAMESPACE_BEGIN 21 | namespace internal { 22 | 23 | //! Computes integer powers of 10 in double (10.0^n). 24 | /*! This function uses lookup table for fast and accurate results. 25 | \param n non-negative exponent. Must <= 308. 26 | \return 10.0^n 27 | */ 28 | inline double Pow10(int n) { 29 | static const double e[] = { // 1e-0...1e308: 309 * 8 bytes = 2472 bytes 30 | 1e+0, 31 | 1e+1, 1e+2, 1e+3, 1e+4, 1e+5, 1e+6, 1e+7, 1e+8, 1e+9, 1e+10, 1e+11, 1e+12, 1e+13, 1e+14, 1e+15, 1e+16, 1e+17, 1e+18, 1e+19, 1e+20, 32 | 1e+21, 1e+22, 1e+23, 1e+24, 1e+25, 1e+26, 1e+27, 1e+28, 1e+29, 1e+30, 1e+31, 1e+32, 1e+33, 1e+34, 1e+35, 1e+36, 1e+37, 1e+38, 1e+39, 1e+40, 33 | 1e+41, 1e+42, 1e+43, 1e+44, 1e+45, 1e+46, 1e+47, 1e+48, 1e+49, 1e+50, 1e+51, 1e+52, 1e+53, 1e+54, 1e+55, 1e+56, 1e+57, 1e+58, 1e+59, 1e+60, 34 | 1e+61, 1e+62, 1e+63, 1e+64, 1e+65, 1e+66, 1e+67, 1e+68, 1e+69, 1e+70, 1e+71, 1e+72, 1e+73, 1e+74, 1e+75, 1e+76, 1e+77, 1e+78, 1e+79, 1e+80, 35 | 1e+81, 1e+82, 1e+83, 1e+84, 1e+85, 1e+86, 1e+87, 1e+88, 1e+89, 1e+90, 1e+91, 1e+92, 1e+93, 1e+94, 1e+95, 1e+96, 1e+97, 1e+98, 1e+99, 1e+100, 36 | 1e+101,1e+102,1e+103,1e+104,1e+105,1e+106,1e+107,1e+108,1e+109,1e+110,1e+111,1e+112,1e+113,1e+114,1e+115,1e+116,1e+117,1e+118,1e+119,1e+120, 37 | 1e+121,1e+122,1e+123,1e+124,1e+125,1e+126,1e+127,1e+128,1e+129,1e+130,1e+131,1e+132,1e+133,1e+134,1e+135,1e+136,1e+137,1e+138,1e+139,1e+140, 38 | 1e+141,1e+142,1e+143,1e+144,1e+145,1e+146,1e+147,1e+148,1e+149,1e+150,1e+151,1e+152,1e+153,1e+154,1e+155,1e+156,1e+157,1e+158,1e+159,1e+160, 39 | 1e+161,1e+162,1e+163,1e+164,1e+165,1e+166,1e+167,1e+168,1e+169,1e+170,1e+171,1e+172,1e+173,1e+174,1e+175,1e+176,1e+177,1e+178,1e+179,1e+180, 40 | 1e+181,1e+182,1e+183,1e+184,1e+185,1e+186,1e+187,1e+188,1e+189,1e+190,1e+191,1e+192,1e+193,1e+194,1e+195,1e+196,1e+197,1e+198,1e+199,1e+200, 41 | 1e+201,1e+202,1e+203,1e+204,1e+205,1e+206,1e+207,1e+208,1e+209,1e+210,1e+211,1e+212,1e+213,1e+214,1e+215,1e+216,1e+217,1e+218,1e+219,1e+220, 42 | 1e+221,1e+222,1e+223,1e+224,1e+225,1e+226,1e+227,1e+228,1e+229,1e+230,1e+231,1e+232,1e+233,1e+234,1e+235,1e+236,1e+237,1e+238,1e+239,1e+240, 43 | 1e+241,1e+242,1e+243,1e+244,1e+245,1e+246,1e+247,1e+248,1e+249,1e+250,1e+251,1e+252,1e+253,1e+254,1e+255,1e+256,1e+257,1e+258,1e+259,1e+260, 44 | 1e+261,1e+262,1e+263,1e+264,1e+265,1e+266,1e+267,1e+268,1e+269,1e+270,1e+271,1e+272,1e+273,1e+274,1e+275,1e+276,1e+277,1e+278,1e+279,1e+280, 45 | 1e+281,1e+282,1e+283,1e+284,1e+285,1e+286,1e+287,1e+288,1e+289,1e+290,1e+291,1e+292,1e+293,1e+294,1e+295,1e+296,1e+297,1e+298,1e+299,1e+300, 46 | 1e+301,1e+302,1e+303,1e+304,1e+305,1e+306,1e+307,1e+308 47 | }; 48 | RAPIDJSON_ASSERT(n >= 0 && n <= 308); 49 | return e[n]; 50 | } 51 | 52 | } // namespace internal 53 | RAPIDJSON_NAMESPACE_END 54 | 55 | #endif // RAPIDJSON_POW10_ 56 | -------------------------------------------------------------------------------- /include/rapidjson/internal/stack.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_INTERNAL_STACK_H_ 16 | #define RAPIDJSON_INTERNAL_STACK_H_ 17 | 18 | #include "../allocators.h" 19 | #include "swap.h" 20 | #include 21 | 22 | #if defined(__clang__) 23 | RAPIDJSON_DIAG_PUSH 24 | RAPIDJSON_DIAG_OFF(c++98-compat) 25 | #endif 26 | 27 | RAPIDJSON_NAMESPACE_BEGIN 28 | namespace internal { 29 | 30 | /////////////////////////////////////////////////////////////////////////////// 31 | // Stack 32 | 33 | //! A type-unsafe stack for storing different types of data. 34 | /*! \tparam Allocator Allocator for allocating stack memory. 35 | */ 36 | template 37 | class Stack { 38 | public: 39 | // Optimization note: Do not allocate memory for stack_ in constructor. 40 | // Do it lazily when first Push() -> Expand() -> Resize(). 41 | Stack(Allocator* allocator, size_t stackCapacity) : allocator_(allocator), ownAllocator_(0), stack_(0), stackTop_(0), stackEnd_(0), initialCapacity_(stackCapacity) { 42 | } 43 | 44 | #if RAPIDJSON_HAS_CXX11_RVALUE_REFS 45 | Stack(Stack&& rhs) 46 | : allocator_(rhs.allocator_), 47 | ownAllocator_(rhs.ownAllocator_), 48 | stack_(rhs.stack_), 49 | stackTop_(rhs.stackTop_), 50 | stackEnd_(rhs.stackEnd_), 51 | initialCapacity_(rhs.initialCapacity_) 52 | { 53 | rhs.allocator_ = 0; 54 | rhs.ownAllocator_ = 0; 55 | rhs.stack_ = 0; 56 | rhs.stackTop_ = 0; 57 | rhs.stackEnd_ = 0; 58 | rhs.initialCapacity_ = 0; 59 | } 60 | #endif 61 | 62 | ~Stack() { 63 | Destroy(); 64 | } 65 | 66 | #if RAPIDJSON_HAS_CXX11_RVALUE_REFS 67 | Stack& operator=(Stack&& rhs) { 68 | if (&rhs != this) 69 | { 70 | Destroy(); 71 | 72 | allocator_ = rhs.allocator_; 73 | ownAllocator_ = rhs.ownAllocator_; 74 | stack_ = rhs.stack_; 75 | stackTop_ = rhs.stackTop_; 76 | stackEnd_ = rhs.stackEnd_; 77 | initialCapacity_ = rhs.initialCapacity_; 78 | 79 | rhs.allocator_ = 0; 80 | rhs.ownAllocator_ = 0; 81 | rhs.stack_ = 0; 82 | rhs.stackTop_ = 0; 83 | rhs.stackEnd_ = 0; 84 | rhs.initialCapacity_ = 0; 85 | } 86 | return *this; 87 | } 88 | #endif 89 | 90 | void Swap(Stack& rhs) RAPIDJSON_NOEXCEPT { 91 | internal::Swap(allocator_, rhs.allocator_); 92 | internal::Swap(ownAllocator_, rhs.ownAllocator_); 93 | internal::Swap(stack_, rhs.stack_); 94 | internal::Swap(stackTop_, rhs.stackTop_); 95 | internal::Swap(stackEnd_, rhs.stackEnd_); 96 | internal::Swap(initialCapacity_, rhs.initialCapacity_); 97 | } 98 | 99 | void Clear() { stackTop_ = stack_; } 100 | 101 | void ShrinkToFit() { 102 | if (Empty()) { 103 | // If the stack is empty, completely deallocate the memory. 104 | Allocator::Free(stack_); // NOLINT (+clang-analyzer-unix.Malloc) 105 | stack_ = 0; 106 | stackTop_ = 0; 107 | stackEnd_ = 0; 108 | } 109 | else 110 | Resize(GetSize()); 111 | } 112 | 113 | // Optimization note: try to minimize the size of this function for force inline. 114 | // Expansion is run very infrequently, so it is moved to another (probably non-inline) function. 115 | template 116 | RAPIDJSON_FORCEINLINE void Reserve(size_t count = 1) { 117 | // Expand the stack if needed 118 | if (RAPIDJSON_UNLIKELY(static_cast(sizeof(T) * count) > (stackEnd_ - stackTop_))) 119 | Expand(count); 120 | } 121 | 122 | template 123 | RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) { 124 | Reserve(count); 125 | return PushUnsafe(count); 126 | } 127 | 128 | template 129 | RAPIDJSON_FORCEINLINE T* PushUnsafe(size_t count = 1) { 130 | RAPIDJSON_ASSERT(stackTop_); 131 | RAPIDJSON_ASSERT(static_cast(sizeof(T) * count) <= (stackEnd_ - stackTop_)); 132 | T* ret = reinterpret_cast(stackTop_); 133 | stackTop_ += sizeof(T) * count; 134 | return ret; 135 | } 136 | 137 | template 138 | T* Pop(size_t count) { 139 | RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T)); 140 | stackTop_ -= count * sizeof(T); 141 | return reinterpret_cast(stackTop_); 142 | } 143 | 144 | template 145 | T* Top() { 146 | RAPIDJSON_ASSERT(GetSize() >= sizeof(T)); 147 | return reinterpret_cast(stackTop_ - sizeof(T)); 148 | } 149 | 150 | template 151 | const T* Top() const { 152 | RAPIDJSON_ASSERT(GetSize() >= sizeof(T)); 153 | return reinterpret_cast(stackTop_ - sizeof(T)); 154 | } 155 | 156 | template 157 | T* End() { return reinterpret_cast(stackTop_); } 158 | 159 | template 160 | const T* End() const { return reinterpret_cast(stackTop_); } 161 | 162 | template 163 | T* Bottom() { return reinterpret_cast(stack_); } 164 | 165 | template 166 | const T* Bottom() const { return reinterpret_cast(stack_); } 167 | 168 | bool HasAllocator() const { 169 | return allocator_ != 0; 170 | } 171 | 172 | Allocator& GetAllocator() { 173 | RAPIDJSON_ASSERT(allocator_); 174 | return *allocator_; 175 | } 176 | 177 | bool Empty() const { return stackTop_ == stack_; } 178 | size_t GetSize() const { return static_cast(stackTop_ - stack_); } 179 | size_t GetCapacity() const { return static_cast(stackEnd_ - stack_); } 180 | 181 | private: 182 | template 183 | void Expand(size_t count) { 184 | // Only expand the capacity if the current stack exists. Otherwise just create a stack with initial capacity. 185 | size_t newCapacity; 186 | if (stack_ == 0) { 187 | if (!allocator_) 188 | ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); 189 | newCapacity = initialCapacity_; 190 | } else { 191 | newCapacity = GetCapacity(); 192 | newCapacity += (newCapacity + 1) / 2; 193 | } 194 | size_t newSize = GetSize() + sizeof(T) * count; 195 | if (newCapacity < newSize) 196 | newCapacity = newSize; 197 | 198 | Resize(newCapacity); 199 | } 200 | 201 | void Resize(size_t newCapacity) { 202 | const size_t size = GetSize(); // Backup the current size 203 | stack_ = static_cast(allocator_->Realloc(stack_, GetCapacity(), newCapacity)); 204 | stackTop_ = stack_ + size; 205 | stackEnd_ = stack_ + newCapacity; 206 | } 207 | 208 | void Destroy() { 209 | Allocator::Free(stack_); 210 | RAPIDJSON_DELETE(ownAllocator_); // Only delete if it is owned by the stack 211 | } 212 | 213 | // Prohibit copy constructor & assignment operator. 214 | Stack(const Stack&); 215 | Stack& operator=(const Stack&); 216 | 217 | Allocator* allocator_; 218 | Allocator* ownAllocator_; 219 | char *stack_; 220 | char *stackTop_; 221 | char *stackEnd_; 222 | size_t initialCapacity_; 223 | }; 224 | 225 | } // namespace internal 226 | RAPIDJSON_NAMESPACE_END 227 | 228 | #if defined(__clang__) 229 | RAPIDJSON_DIAG_POP 230 | #endif 231 | 232 | #endif // RAPIDJSON_STACK_H_ 233 | -------------------------------------------------------------------------------- /include/rapidjson/internal/strfunc.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_INTERNAL_STRFUNC_H_ 16 | #define RAPIDJSON_INTERNAL_STRFUNC_H_ 17 | 18 | #include "../stream.h" 19 | #include 20 | 21 | RAPIDJSON_NAMESPACE_BEGIN 22 | namespace internal { 23 | 24 | //! Custom strlen() which works on different character types. 25 | /*! \tparam Ch Character type (e.g. char, wchar_t, short) 26 | \param s Null-terminated input string. 27 | \return Number of characters in the string. 28 | \note This has the same semantics as strlen(), the return value is not number of Unicode codepoints. 29 | */ 30 | template 31 | inline SizeType StrLen(const Ch* s) { 32 | RAPIDJSON_ASSERT(s != 0); 33 | const Ch* p = s; 34 | while (*p) ++p; 35 | return SizeType(p - s); 36 | } 37 | 38 | template <> 39 | inline SizeType StrLen(const char* s) { 40 | return SizeType(std::strlen(s)); 41 | } 42 | 43 | template <> 44 | inline SizeType StrLen(const wchar_t* s) { 45 | return SizeType(std::wcslen(s)); 46 | } 47 | 48 | //! Returns number of code points in a encoded string. 49 | template 50 | bool CountStringCodePoint(const typename Encoding::Ch* s, SizeType length, SizeType* outCount) { 51 | RAPIDJSON_ASSERT(s != 0); 52 | RAPIDJSON_ASSERT(outCount != 0); 53 | GenericStringStream is(s); 54 | const typename Encoding::Ch* end = s + length; 55 | SizeType count = 0; 56 | while (is.src_ < end) { 57 | unsigned codepoint; 58 | if (!Encoding::Decode(is, &codepoint)) 59 | return false; 60 | count++; 61 | } 62 | *outCount = count; 63 | return true; 64 | } 65 | 66 | } // namespace internal 67 | RAPIDJSON_NAMESPACE_END 68 | 69 | #endif // RAPIDJSON_INTERNAL_STRFUNC_H_ 70 | -------------------------------------------------------------------------------- /include/rapidjson/internal/swap.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_INTERNAL_SWAP_H_ 16 | #define RAPIDJSON_INTERNAL_SWAP_H_ 17 | 18 | #include "../rapidjson.h" 19 | 20 | #if defined(__clang__) 21 | RAPIDJSON_DIAG_PUSH 22 | RAPIDJSON_DIAG_OFF(c++98-compat) 23 | #endif 24 | 25 | RAPIDJSON_NAMESPACE_BEGIN 26 | namespace internal { 27 | 28 | //! Custom swap() to avoid dependency on C++ header 29 | /*! \tparam T Type of the arguments to swap, should be instantiated with primitive C++ types only. 30 | \note This has the same semantics as std::swap(). 31 | */ 32 | template 33 | inline void Swap(T& a, T& b) RAPIDJSON_NOEXCEPT { 34 | T tmp = a; 35 | a = b; 36 | b = tmp; 37 | } 38 | 39 | } // namespace internal 40 | RAPIDJSON_NAMESPACE_END 41 | 42 | #if defined(__clang__) 43 | RAPIDJSON_DIAG_POP 44 | #endif 45 | 46 | #endif // RAPIDJSON_INTERNAL_SWAP_H_ 47 | -------------------------------------------------------------------------------- /include/rapidjson/istreamwrapper.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_ISTREAMWRAPPER_H_ 16 | #define RAPIDJSON_ISTREAMWRAPPER_H_ 17 | 18 | #include "stream.h" 19 | #include 20 | #include 21 | 22 | #ifdef __clang__ 23 | RAPIDJSON_DIAG_PUSH 24 | RAPIDJSON_DIAG_OFF(padded) 25 | #elif defined(_MSC_VER) 26 | RAPIDJSON_DIAG_PUSH 27 | RAPIDJSON_DIAG_OFF(4351) // new behavior: elements of array 'array' will be default initialized 28 | #endif 29 | 30 | RAPIDJSON_NAMESPACE_BEGIN 31 | 32 | //! Wrapper of \c std::basic_istream into RapidJSON's Stream concept. 33 | /*! 34 | The classes can be wrapped including but not limited to: 35 | 36 | - \c std::istringstream 37 | - \c std::stringstream 38 | - \c std::wistringstream 39 | - \c std::wstringstream 40 | - \c std::ifstream 41 | - \c std::fstream 42 | - \c std::wifstream 43 | - \c std::wfstream 44 | 45 | \tparam StreamType Class derived from \c std::basic_istream. 46 | */ 47 | 48 | template 49 | class BasicIStreamWrapper { 50 | public: 51 | typedef typename StreamType::char_type Ch; 52 | 53 | //! Constructor. 54 | /*! 55 | \param stream stream opened for read. 56 | */ 57 | BasicIStreamWrapper(StreamType &stream) : stream_(stream), buffer_(peekBuffer_), bufferSize_(4), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) { 58 | Read(); 59 | } 60 | 61 | //! Constructor. 62 | /*! 63 | \param stream stream opened for read. 64 | \param buffer user-supplied buffer. 65 | \param bufferSize size of buffer in bytes. Must >=4 bytes. 66 | */ 67 | BasicIStreamWrapper(StreamType &stream, char* buffer, size_t bufferSize) : stream_(stream), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) { 68 | RAPIDJSON_ASSERT(bufferSize >= 4); 69 | Read(); 70 | } 71 | 72 | Ch Peek() const { return *current_; } 73 | Ch Take() { Ch c = *current_; Read(); return c; } 74 | size_t Tell() const { return count_ + static_cast(current_ - buffer_); } 75 | 76 | // Not implemented 77 | void Put(Ch) { RAPIDJSON_ASSERT(false); } 78 | void Flush() { RAPIDJSON_ASSERT(false); } 79 | Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } 80 | size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } 81 | 82 | // For encoding detection only. 83 | const Ch* Peek4() const { 84 | return (current_ + 4 - !eof_ <= bufferLast_) ? current_ : 0; 85 | } 86 | 87 | private: 88 | BasicIStreamWrapper(); 89 | BasicIStreamWrapper(const BasicIStreamWrapper&); 90 | BasicIStreamWrapper& operator=(const BasicIStreamWrapper&); 91 | 92 | void Read() { 93 | if (current_ < bufferLast_) 94 | ++current_; 95 | else if (!eof_) { 96 | count_ += readCount_; 97 | readCount_ = bufferSize_; 98 | bufferLast_ = buffer_ + readCount_ - 1; 99 | current_ = buffer_; 100 | 101 | if (!stream_.read(buffer_, static_cast(bufferSize_))) { 102 | readCount_ = static_cast(stream_.gcount()); 103 | *(bufferLast_ = buffer_ + readCount_) = '\0'; 104 | eof_ = true; 105 | } 106 | } 107 | } 108 | 109 | StreamType &stream_; 110 | Ch peekBuffer_[4], *buffer_; 111 | size_t bufferSize_; 112 | Ch *bufferLast_; 113 | Ch *current_; 114 | size_t readCount_; 115 | size_t count_; //!< Number of characters read 116 | bool eof_; 117 | }; 118 | 119 | typedef BasicIStreamWrapper IStreamWrapper; 120 | typedef BasicIStreamWrapper WIStreamWrapper; 121 | 122 | #if defined(__clang__) || defined(_MSC_VER) 123 | RAPIDJSON_DIAG_POP 124 | #endif 125 | 126 | RAPIDJSON_NAMESPACE_END 127 | 128 | #endif // RAPIDJSON_ISTREAMWRAPPER_H_ 129 | -------------------------------------------------------------------------------- /include/rapidjson/memorybuffer.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_MEMORYBUFFER_H_ 16 | #define RAPIDJSON_MEMORYBUFFER_H_ 17 | 18 | #include "stream.h" 19 | #include "internal/stack.h" 20 | 21 | RAPIDJSON_NAMESPACE_BEGIN 22 | 23 | //! Represents an in-memory output byte stream. 24 | /*! 25 | This class is mainly for being wrapped by EncodedOutputStream or AutoUTFOutputStream. 26 | 27 | It is similar to FileWriteBuffer but the destination is an in-memory buffer instead of a file. 28 | 29 | Differences between MemoryBuffer and StringBuffer: 30 | 1. StringBuffer has Encoding but MemoryBuffer is only a byte buffer. 31 | 2. StringBuffer::GetString() returns a null-terminated string. MemoryBuffer::GetBuffer() returns a buffer without terminator. 32 | 33 | \tparam Allocator type for allocating memory buffer. 34 | \note implements Stream concept 35 | */ 36 | template 37 | struct GenericMemoryBuffer { 38 | typedef char Ch; // byte 39 | 40 | GenericMemoryBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {} 41 | 42 | void Put(Ch c) { *stack_.template Push() = c; } 43 | void Flush() {} 44 | 45 | void Clear() { stack_.Clear(); } 46 | void ShrinkToFit() { stack_.ShrinkToFit(); } 47 | Ch* Push(size_t count) { return stack_.template Push(count); } 48 | void Pop(size_t count) { stack_.template Pop(count); } 49 | 50 | const Ch* GetBuffer() const { 51 | return stack_.template Bottom(); 52 | } 53 | 54 | size_t GetSize() const { return stack_.GetSize(); } 55 | 56 | static const size_t kDefaultCapacity = 256; 57 | mutable internal::Stack stack_; 58 | }; 59 | 60 | typedef GenericMemoryBuffer<> MemoryBuffer; 61 | 62 | //! Implement specialized version of PutN() with memset() for better performance. 63 | template<> 64 | inline void PutN(MemoryBuffer& memoryBuffer, char c, size_t n) { 65 | std::memset(memoryBuffer.stack_.Push(n), c, n * sizeof(c)); 66 | } 67 | 68 | RAPIDJSON_NAMESPACE_END 69 | 70 | #endif // RAPIDJSON_MEMORYBUFFER_H_ 71 | -------------------------------------------------------------------------------- /include/rapidjson/memorystream.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_MEMORYSTREAM_H_ 16 | #define RAPIDJSON_MEMORYSTREAM_H_ 17 | 18 | #include "stream.h" 19 | 20 | #ifdef __clang__ 21 | RAPIDJSON_DIAG_PUSH 22 | RAPIDJSON_DIAG_OFF(unreachable-code) 23 | RAPIDJSON_DIAG_OFF(missing-noreturn) 24 | #endif 25 | 26 | RAPIDJSON_NAMESPACE_BEGIN 27 | 28 | //! Represents an in-memory input byte stream. 29 | /*! 30 | This class is mainly for being wrapped by EncodedInputStream or AutoUTFInputStream. 31 | 32 | It is similar to FileReadBuffer but the source is an in-memory buffer instead of a file. 33 | 34 | Differences between MemoryStream and StringStream: 35 | 1. StringStream has encoding but MemoryStream is a byte stream. 36 | 2. MemoryStream needs size of the source buffer and the buffer don't need to be null terminated. StringStream assume null-terminated string as source. 37 | 3. MemoryStream supports Peek4() for encoding detection. StringStream is specified with an encoding so it should not have Peek4(). 38 | \note implements Stream concept 39 | */ 40 | struct MemoryStream { 41 | typedef char Ch; // byte 42 | 43 | MemoryStream(const Ch *src, size_t size) : src_(src), begin_(src), end_(src + size), size_(size) {} 44 | 45 | Ch Peek() const { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_; } 46 | Ch Take() { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_++; } 47 | size_t Tell() const { return static_cast(src_ - begin_); } 48 | 49 | Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } 50 | void Put(Ch) { RAPIDJSON_ASSERT(false); } 51 | void Flush() { RAPIDJSON_ASSERT(false); } 52 | size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } 53 | 54 | // For encoding detection only. 55 | const Ch* Peek4() const { 56 | return Tell() + 4 <= size_ ? src_ : 0; 57 | } 58 | 59 | const Ch* src_; //!< Current read position. 60 | const Ch* begin_; //!< Original head of the string. 61 | const Ch* end_; //!< End of stream. 62 | size_t size_; //!< Size of the stream. 63 | }; 64 | 65 | RAPIDJSON_NAMESPACE_END 66 | 67 | #ifdef __clang__ 68 | RAPIDJSON_DIAG_POP 69 | #endif 70 | 71 | #endif // RAPIDJSON_MEMORYBUFFER_H_ 72 | -------------------------------------------------------------------------------- /include/rapidjson/msinttypes/inttypes.h: -------------------------------------------------------------------------------- 1 | // ISO C9x compliant inttypes.h for Microsoft Visual Studio 2 | // Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 3 | // 4 | // Copyright (c) 2006-2013 Alexander Chemeris 5 | // 6 | // Redistribution and use in source and binary forms, with or without 7 | // modification, are permitted provided that the following conditions are met: 8 | // 9 | // 1. Redistributions of source code must retain the above copyright notice, 10 | // this list of conditions and the following disclaimer. 11 | // 12 | // 2. Redistributions in binary form must reproduce the above copyright 13 | // notice, this list of conditions and the following disclaimer in the 14 | // documentation and/or other materials provided with the distribution. 15 | // 16 | // 3. Neither the name of the product nor the names of its contributors may 17 | // be used to endorse or promote products derived from this software 18 | // without specific prior written permission. 19 | // 20 | // THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 21 | // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 22 | // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 23 | // EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 26 | // OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 27 | // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 28 | // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 29 | // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | // 31 | /////////////////////////////////////////////////////////////////////////////// 32 | 33 | // The above software in this distribution may have been modified by 34 | // THL A29 Limited ("Tencent Modifications"). 35 | // All Tencent Modifications are Copyright (C) 2015 THL A29 Limited. 36 | 37 | #ifndef _MSC_VER // [ 38 | #error "Use this header only with Microsoft Visual C++ compilers!" 39 | #endif // _MSC_VER ] 40 | 41 | #ifndef _MSC_INTTYPES_H_ // [ 42 | #define _MSC_INTTYPES_H_ 43 | 44 | #if _MSC_VER > 1000 45 | #pragma once 46 | #endif 47 | 48 | #include "stdint.h" 49 | 50 | // miloyip: VC supports inttypes.h since VC2013 51 | #if _MSC_VER >= 1800 52 | #include 53 | #else 54 | 55 | // 7.8 Format conversion of integer types 56 | 57 | typedef struct { 58 | intmax_t quot; 59 | intmax_t rem; 60 | } imaxdiv_t; 61 | 62 | // 7.8.1 Macros for format specifiers 63 | 64 | #if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) // [ See footnote 185 at page 198 65 | 66 | // The fprintf macros for signed integers are: 67 | #define PRId8 "d" 68 | #define PRIi8 "i" 69 | #define PRIdLEAST8 "d" 70 | #define PRIiLEAST8 "i" 71 | #define PRIdFAST8 "d" 72 | #define PRIiFAST8 "i" 73 | 74 | #define PRId16 "hd" 75 | #define PRIi16 "hi" 76 | #define PRIdLEAST16 "hd" 77 | #define PRIiLEAST16 "hi" 78 | #define PRIdFAST16 "hd" 79 | #define PRIiFAST16 "hi" 80 | 81 | #define PRId32 "I32d" 82 | #define PRIi32 "I32i" 83 | #define PRIdLEAST32 "I32d" 84 | #define PRIiLEAST32 "I32i" 85 | #define PRIdFAST32 "I32d" 86 | #define PRIiFAST32 "I32i" 87 | 88 | #define PRId64 "I64d" 89 | #define PRIi64 "I64i" 90 | #define PRIdLEAST64 "I64d" 91 | #define PRIiLEAST64 "I64i" 92 | #define PRIdFAST64 "I64d" 93 | #define PRIiFAST64 "I64i" 94 | 95 | #define PRIdMAX "I64d" 96 | #define PRIiMAX "I64i" 97 | 98 | #define PRIdPTR "Id" 99 | #define PRIiPTR "Ii" 100 | 101 | // The fprintf macros for unsigned integers are: 102 | #define PRIo8 "o" 103 | #define PRIu8 "u" 104 | #define PRIx8 "x" 105 | #define PRIX8 "X" 106 | #define PRIoLEAST8 "o" 107 | #define PRIuLEAST8 "u" 108 | #define PRIxLEAST8 "x" 109 | #define PRIXLEAST8 "X" 110 | #define PRIoFAST8 "o" 111 | #define PRIuFAST8 "u" 112 | #define PRIxFAST8 "x" 113 | #define PRIXFAST8 "X" 114 | 115 | #define PRIo16 "ho" 116 | #define PRIu16 "hu" 117 | #define PRIx16 "hx" 118 | #define PRIX16 "hX" 119 | #define PRIoLEAST16 "ho" 120 | #define PRIuLEAST16 "hu" 121 | #define PRIxLEAST16 "hx" 122 | #define PRIXLEAST16 "hX" 123 | #define PRIoFAST16 "ho" 124 | #define PRIuFAST16 "hu" 125 | #define PRIxFAST16 "hx" 126 | #define PRIXFAST16 "hX" 127 | 128 | #define PRIo32 "I32o" 129 | #define PRIu32 "I32u" 130 | #define PRIx32 "I32x" 131 | #define PRIX32 "I32X" 132 | #define PRIoLEAST32 "I32o" 133 | #define PRIuLEAST32 "I32u" 134 | #define PRIxLEAST32 "I32x" 135 | #define PRIXLEAST32 "I32X" 136 | #define PRIoFAST32 "I32o" 137 | #define PRIuFAST32 "I32u" 138 | #define PRIxFAST32 "I32x" 139 | #define PRIXFAST32 "I32X" 140 | 141 | #define PRIo64 "I64o" 142 | #define PRIu64 "I64u" 143 | #define PRIx64 "I64x" 144 | #define PRIX64 "I64X" 145 | #define PRIoLEAST64 "I64o" 146 | #define PRIuLEAST64 "I64u" 147 | #define PRIxLEAST64 "I64x" 148 | #define PRIXLEAST64 "I64X" 149 | #define PRIoFAST64 "I64o" 150 | #define PRIuFAST64 "I64u" 151 | #define PRIxFAST64 "I64x" 152 | #define PRIXFAST64 "I64X" 153 | 154 | #define PRIoMAX "I64o" 155 | #define PRIuMAX "I64u" 156 | #define PRIxMAX "I64x" 157 | #define PRIXMAX "I64X" 158 | 159 | #define PRIoPTR "Io" 160 | #define PRIuPTR "Iu" 161 | #define PRIxPTR "Ix" 162 | #define PRIXPTR "IX" 163 | 164 | // The fscanf macros for signed integers are: 165 | #define SCNd8 "d" 166 | #define SCNi8 "i" 167 | #define SCNdLEAST8 "d" 168 | #define SCNiLEAST8 "i" 169 | #define SCNdFAST8 "d" 170 | #define SCNiFAST8 "i" 171 | 172 | #define SCNd16 "hd" 173 | #define SCNi16 "hi" 174 | #define SCNdLEAST16 "hd" 175 | #define SCNiLEAST16 "hi" 176 | #define SCNdFAST16 "hd" 177 | #define SCNiFAST16 "hi" 178 | 179 | #define SCNd32 "ld" 180 | #define SCNi32 "li" 181 | #define SCNdLEAST32 "ld" 182 | #define SCNiLEAST32 "li" 183 | #define SCNdFAST32 "ld" 184 | #define SCNiFAST32 "li" 185 | 186 | #define SCNd64 "I64d" 187 | #define SCNi64 "I64i" 188 | #define SCNdLEAST64 "I64d" 189 | #define SCNiLEAST64 "I64i" 190 | #define SCNdFAST64 "I64d" 191 | #define SCNiFAST64 "I64i" 192 | 193 | #define SCNdMAX "I64d" 194 | #define SCNiMAX "I64i" 195 | 196 | #ifdef _WIN64 // [ 197 | # define SCNdPTR "I64d" 198 | # define SCNiPTR "I64i" 199 | #else // _WIN64 ][ 200 | # define SCNdPTR "ld" 201 | # define SCNiPTR "li" 202 | #endif // _WIN64 ] 203 | 204 | // The fscanf macros for unsigned integers are: 205 | #define SCNo8 "o" 206 | #define SCNu8 "u" 207 | #define SCNx8 "x" 208 | #define SCNX8 "X" 209 | #define SCNoLEAST8 "o" 210 | #define SCNuLEAST8 "u" 211 | #define SCNxLEAST8 "x" 212 | #define SCNXLEAST8 "X" 213 | #define SCNoFAST8 "o" 214 | #define SCNuFAST8 "u" 215 | #define SCNxFAST8 "x" 216 | #define SCNXFAST8 "X" 217 | 218 | #define SCNo16 "ho" 219 | #define SCNu16 "hu" 220 | #define SCNx16 "hx" 221 | #define SCNX16 "hX" 222 | #define SCNoLEAST16 "ho" 223 | #define SCNuLEAST16 "hu" 224 | #define SCNxLEAST16 "hx" 225 | #define SCNXLEAST16 "hX" 226 | #define SCNoFAST16 "ho" 227 | #define SCNuFAST16 "hu" 228 | #define SCNxFAST16 "hx" 229 | #define SCNXFAST16 "hX" 230 | 231 | #define SCNo32 "lo" 232 | #define SCNu32 "lu" 233 | #define SCNx32 "lx" 234 | #define SCNX32 "lX" 235 | #define SCNoLEAST32 "lo" 236 | #define SCNuLEAST32 "lu" 237 | #define SCNxLEAST32 "lx" 238 | #define SCNXLEAST32 "lX" 239 | #define SCNoFAST32 "lo" 240 | #define SCNuFAST32 "lu" 241 | #define SCNxFAST32 "lx" 242 | #define SCNXFAST32 "lX" 243 | 244 | #define SCNo64 "I64o" 245 | #define SCNu64 "I64u" 246 | #define SCNx64 "I64x" 247 | #define SCNX64 "I64X" 248 | #define SCNoLEAST64 "I64o" 249 | #define SCNuLEAST64 "I64u" 250 | #define SCNxLEAST64 "I64x" 251 | #define SCNXLEAST64 "I64X" 252 | #define SCNoFAST64 "I64o" 253 | #define SCNuFAST64 "I64u" 254 | #define SCNxFAST64 "I64x" 255 | #define SCNXFAST64 "I64X" 256 | 257 | #define SCNoMAX "I64o" 258 | #define SCNuMAX "I64u" 259 | #define SCNxMAX "I64x" 260 | #define SCNXMAX "I64X" 261 | 262 | #ifdef _WIN64 // [ 263 | # define SCNoPTR "I64o" 264 | # define SCNuPTR "I64u" 265 | # define SCNxPTR "I64x" 266 | # define SCNXPTR "I64X" 267 | #else // _WIN64 ][ 268 | # define SCNoPTR "lo" 269 | # define SCNuPTR "lu" 270 | # define SCNxPTR "lx" 271 | # define SCNXPTR "lX" 272 | #endif // _WIN64 ] 273 | 274 | #endif // __STDC_FORMAT_MACROS ] 275 | 276 | // 7.8.2 Functions for greatest-width integer types 277 | 278 | // 7.8.2.1 The imaxabs function 279 | #define imaxabs _abs64 280 | 281 | // 7.8.2.2 The imaxdiv function 282 | 283 | // This is modified version of div() function from Microsoft's div.c found 284 | // in %MSVC.NET%\crt\src\div.c 285 | #ifdef STATIC_IMAXDIV // [ 286 | static 287 | #else // STATIC_IMAXDIV ][ 288 | _inline 289 | #endif // STATIC_IMAXDIV ] 290 | imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom) 291 | { 292 | imaxdiv_t result; 293 | 294 | result.quot = numer / denom; 295 | result.rem = numer % denom; 296 | 297 | if (numer < 0 && result.rem > 0) { 298 | // did division wrong; must fix up 299 | ++result.quot; 300 | result.rem -= denom; 301 | } 302 | 303 | return result; 304 | } 305 | 306 | // 7.8.2.3 The strtoimax and strtoumax functions 307 | #define strtoimax _strtoi64 308 | #define strtoumax _strtoui64 309 | 310 | // 7.8.2.4 The wcstoimax and wcstoumax functions 311 | #define wcstoimax _wcstoi64 312 | #define wcstoumax _wcstoui64 313 | 314 | #endif // _MSC_VER >= 1800 315 | 316 | #endif // _MSC_INTTYPES_H_ ] 317 | -------------------------------------------------------------------------------- /include/rapidjson/ostreamwrapper.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_OSTREAMWRAPPER_H_ 16 | #define RAPIDJSON_OSTREAMWRAPPER_H_ 17 | 18 | #include "stream.h" 19 | #include 20 | 21 | #ifdef __clang__ 22 | RAPIDJSON_DIAG_PUSH 23 | RAPIDJSON_DIAG_OFF(padded) 24 | #endif 25 | 26 | RAPIDJSON_NAMESPACE_BEGIN 27 | 28 | //! Wrapper of \c std::basic_ostream into RapidJSON's Stream concept. 29 | /*! 30 | The classes can be wrapped including but not limited to: 31 | 32 | - \c std::ostringstream 33 | - \c std::stringstream 34 | - \c std::wpstringstream 35 | - \c std::wstringstream 36 | - \c std::ifstream 37 | - \c std::fstream 38 | - \c std::wofstream 39 | - \c std::wfstream 40 | 41 | \tparam StreamType Class derived from \c std::basic_ostream. 42 | */ 43 | 44 | template 45 | class BasicOStreamWrapper { 46 | public: 47 | typedef typename StreamType::char_type Ch; 48 | BasicOStreamWrapper(StreamType& stream) : stream_(stream) {} 49 | 50 | void Put(Ch c) { 51 | stream_.put(c); 52 | } 53 | 54 | void Flush() { 55 | stream_.flush(); 56 | } 57 | 58 | // Not implemented 59 | char Peek() const { RAPIDJSON_ASSERT(false); return 0; } 60 | char Take() { RAPIDJSON_ASSERT(false); return 0; } 61 | size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } 62 | char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } 63 | size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; } 64 | 65 | private: 66 | BasicOStreamWrapper(const BasicOStreamWrapper&); 67 | BasicOStreamWrapper& operator=(const BasicOStreamWrapper&); 68 | 69 | StreamType& stream_; 70 | }; 71 | 72 | typedef BasicOStreamWrapper OStreamWrapper; 73 | typedef BasicOStreamWrapper WOStreamWrapper; 74 | 75 | #ifdef __clang__ 76 | RAPIDJSON_DIAG_POP 77 | #endif 78 | 79 | RAPIDJSON_NAMESPACE_END 80 | 81 | #endif // RAPIDJSON_OSTREAMWRAPPER_H_ 82 | -------------------------------------------------------------------------------- /include/rapidjson/stream.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #include "rapidjson.h" 16 | 17 | #ifndef RAPIDJSON_STREAM_H_ 18 | #define RAPIDJSON_STREAM_H_ 19 | 20 | #include "encodings.h" 21 | 22 | RAPIDJSON_NAMESPACE_BEGIN 23 | 24 | /////////////////////////////////////////////////////////////////////////////// 25 | // Stream 26 | 27 | /*! \class rapidjson::Stream 28 | \brief Concept for reading and writing characters. 29 | 30 | For read-only stream, no need to implement PutBegin(), Put(), Flush() and PutEnd(). 31 | 32 | For write-only stream, only need to implement Put() and Flush(). 33 | 34 | \code 35 | concept Stream { 36 | typename Ch; //!< Character type of the stream. 37 | 38 | //! Read the current character from stream without moving the read cursor. 39 | Ch Peek() const; 40 | 41 | //! Read the current character from stream and moving the read cursor to next character. 42 | Ch Take(); 43 | 44 | //! Get the current read cursor. 45 | //! \return Number of characters read from start. 46 | size_t Tell(); 47 | 48 | //! Begin writing operation at the current read pointer. 49 | //! \return The begin writer pointer. 50 | Ch* PutBegin(); 51 | 52 | //! Write a character. 53 | void Put(Ch c); 54 | 55 | //! Flush the buffer. 56 | void Flush(); 57 | 58 | //! End the writing operation. 59 | //! \param begin The begin write pointer returned by PutBegin(). 60 | //! \return Number of characters written. 61 | size_t PutEnd(Ch* begin); 62 | } 63 | \endcode 64 | */ 65 | 66 | //! Provides additional information for stream. 67 | /*! 68 | By using traits pattern, this type provides a default configuration for stream. 69 | For custom stream, this type can be specialized for other configuration. 70 | See TEST(Reader, CustomStringStream) in readertest.cpp for example. 71 | */ 72 | template 73 | struct StreamTraits { 74 | //! Whether to make local copy of stream for optimization during parsing. 75 | /*! 76 | By default, for safety, streams do not use local copy optimization. 77 | Stream that can be copied fast should specialize this, like StreamTraits. 78 | */ 79 | enum { copyOptimization = 0 }; 80 | }; 81 | 82 | //! Reserve n characters for writing to a stream. 83 | template 84 | inline void PutReserve(Stream& stream, size_t count) { 85 | (void)stream; 86 | (void)count; 87 | } 88 | 89 | //! Write character to a stream, presuming buffer is reserved. 90 | template 91 | inline void PutUnsafe(Stream& stream, typename Stream::Ch c) { 92 | stream.Put(c); 93 | } 94 | 95 | //! Put N copies of a character to a stream. 96 | template 97 | inline void PutN(Stream& stream, Ch c, size_t n) { 98 | PutReserve(stream, n); 99 | for (size_t i = 0; i < n; i++) 100 | PutUnsafe(stream, c); 101 | } 102 | 103 | /////////////////////////////////////////////////////////////////////////////// 104 | // GenericStreamWrapper 105 | 106 | //! A Stream Wrapper 107 | /*! \tThis string stream is a wrapper for any stream by just forwarding any 108 | \treceived message to the origin stream. 109 | \note implements Stream concept 110 | */ 111 | 112 | #if defined(_MSC_VER) && _MSC_VER <= 1800 113 | RAPIDJSON_DIAG_PUSH 114 | RAPIDJSON_DIAG_OFF(4702) // unreachable code 115 | RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated 116 | #endif 117 | 118 | template > 119 | class GenericStreamWrapper { 120 | public: 121 | typedef typename Encoding::Ch Ch; 122 | GenericStreamWrapper(InputStream& is): is_(is) {} 123 | 124 | Ch Peek() const { return is_.Peek(); } 125 | Ch Take() { return is_.Take(); } 126 | size_t Tell() { return is_.Tell(); } 127 | Ch* PutBegin() { return is_.PutBegin(); } 128 | void Put(Ch ch) { is_.Put(ch); } 129 | void Flush() { is_.Flush(); } 130 | size_t PutEnd(Ch* ch) { return is_.PutEnd(ch); } 131 | 132 | // wrapper for MemoryStream 133 | const Ch* Peek4() const { return is_.Peek4(); } 134 | 135 | // wrapper for AutoUTFInputStream 136 | UTFType GetType() const { return is_.GetType(); } 137 | bool HasBOM() const { return is_.HasBOM(); } 138 | 139 | protected: 140 | InputStream& is_; 141 | }; 142 | 143 | #if defined(_MSC_VER) && _MSC_VER <= 1800 144 | RAPIDJSON_DIAG_POP 145 | #endif 146 | 147 | /////////////////////////////////////////////////////////////////////////////// 148 | // StringStream 149 | 150 | //! Read-only string stream. 151 | /*! \note implements Stream concept 152 | */ 153 | template 154 | struct GenericStringStream { 155 | typedef typename Encoding::Ch Ch; 156 | 157 | GenericStringStream(const Ch *src) : src_(src), head_(src) {} 158 | 159 | Ch Peek() const { return *src_; } 160 | Ch Take() { return *src_++; } 161 | size_t Tell() const { return static_cast(src_ - head_); } 162 | 163 | Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } 164 | void Put(Ch) { RAPIDJSON_ASSERT(false); } 165 | void Flush() { RAPIDJSON_ASSERT(false); } 166 | size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } 167 | 168 | const Ch* src_; //!< Current read position. 169 | const Ch* head_; //!< Original head of the string. 170 | }; 171 | 172 | template 173 | struct StreamTraits > { 174 | enum { copyOptimization = 1 }; 175 | }; 176 | 177 | //! String stream with UTF8 encoding. 178 | typedef GenericStringStream > StringStream; 179 | 180 | /////////////////////////////////////////////////////////////////////////////// 181 | // InsituStringStream 182 | 183 | //! A read-write string stream. 184 | /*! This string stream is particularly designed for in-situ parsing. 185 | \note implements Stream concept 186 | */ 187 | template 188 | struct GenericInsituStringStream { 189 | typedef typename Encoding::Ch Ch; 190 | 191 | GenericInsituStringStream(Ch *src) : src_(src), dst_(0), head_(src) {} 192 | 193 | // Read 194 | Ch Peek() { return *src_; } 195 | Ch Take() { return *src_++; } 196 | size_t Tell() { return static_cast(src_ - head_); } 197 | 198 | // Write 199 | void Put(Ch c) { RAPIDJSON_ASSERT(dst_ != 0); *dst_++ = c; } 200 | 201 | Ch* PutBegin() { return dst_ = src_; } 202 | size_t PutEnd(Ch* begin) { return static_cast(dst_ - begin); } 203 | void Flush() {} 204 | 205 | Ch* Push(size_t count) { Ch* begin = dst_; dst_ += count; return begin; } 206 | void Pop(size_t count) { dst_ -= count; } 207 | 208 | Ch* src_; 209 | Ch* dst_; 210 | Ch* head_; 211 | }; 212 | 213 | template 214 | struct StreamTraits > { 215 | enum { copyOptimization = 1 }; 216 | }; 217 | 218 | //! Insitu string stream with UTF8 encoding. 219 | typedef GenericInsituStringStream > InsituStringStream; 220 | 221 | RAPIDJSON_NAMESPACE_END 222 | 223 | #endif // RAPIDJSON_STREAM_H_ 224 | -------------------------------------------------------------------------------- /include/rapidjson/stringbuffer.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_STRINGBUFFER_H_ 16 | #define RAPIDJSON_STRINGBUFFER_H_ 17 | 18 | #include "stream.h" 19 | #include "internal/stack.h" 20 | 21 | #if RAPIDJSON_HAS_CXX11_RVALUE_REFS 22 | #include // std::move 23 | #endif 24 | 25 | #include "internal/stack.h" 26 | 27 | #if defined(__clang__) 28 | RAPIDJSON_DIAG_PUSH 29 | RAPIDJSON_DIAG_OFF(c++98-compat) 30 | #endif 31 | 32 | RAPIDJSON_NAMESPACE_BEGIN 33 | 34 | //! Represents an in-memory output stream. 35 | /*! 36 | \tparam Encoding Encoding of the stream. 37 | \tparam Allocator type for allocating memory buffer. 38 | \note implements Stream concept 39 | */ 40 | template 41 | class GenericStringBuffer { 42 | public: 43 | typedef typename Encoding::Ch Ch; 44 | 45 | GenericStringBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {} 46 | 47 | #if RAPIDJSON_HAS_CXX11_RVALUE_REFS 48 | GenericStringBuffer(GenericStringBuffer&& rhs) : stack_(std::move(rhs.stack_)) {} 49 | GenericStringBuffer& operator=(GenericStringBuffer&& rhs) { 50 | if (&rhs != this) 51 | stack_ = std::move(rhs.stack_); 52 | return *this; 53 | } 54 | #endif 55 | 56 | void Put(Ch c) { *stack_.template Push() = c; } 57 | void PutUnsafe(Ch c) { *stack_.template PushUnsafe() = c; } 58 | void Flush() {} 59 | 60 | void Clear() { stack_.Clear(); } 61 | void ShrinkToFit() { 62 | // Push and pop a null terminator. This is safe. 63 | *stack_.template Push() = '\0'; 64 | stack_.ShrinkToFit(); 65 | stack_.template Pop(1); 66 | } 67 | 68 | void Reserve(size_t count) { stack_.template Reserve(count); } 69 | Ch* Push(size_t count) { return stack_.template Push(count); } 70 | Ch* PushUnsafe(size_t count) { return stack_.template PushUnsafe(count); } 71 | void Pop(size_t count) { stack_.template Pop(count); } 72 | 73 | const Ch* GetString() const { 74 | // Push and pop a null terminator. This is safe. 75 | *stack_.template Push() = '\0'; 76 | stack_.template Pop(1); 77 | 78 | return stack_.template Bottom(); 79 | } 80 | 81 | //! Get the size of string in bytes in the string buffer. 82 | size_t GetSize() const { return stack_.GetSize(); } 83 | 84 | //! Get the length of string in Ch in the string buffer. 85 | size_t GetLength() const { return stack_.GetSize() / sizeof(Ch); } 86 | 87 | static const size_t kDefaultCapacity = 256; 88 | mutable internal::Stack stack_; 89 | 90 | private: 91 | // Prohibit copy constructor & assignment operator. 92 | GenericStringBuffer(const GenericStringBuffer&); 93 | GenericStringBuffer& operator=(const GenericStringBuffer&); 94 | }; 95 | 96 | //! String buffer with UTF8 encoding 97 | typedef GenericStringBuffer > StringBuffer; 98 | 99 | template 100 | inline void PutReserve(GenericStringBuffer& stream, size_t count) { 101 | stream.Reserve(count); 102 | } 103 | 104 | template 105 | inline void PutUnsafe(GenericStringBuffer& stream, typename Encoding::Ch c) { 106 | stream.PutUnsafe(c); 107 | } 108 | 109 | //! Implement specialized version of PutN() with memset() for better performance. 110 | template<> 111 | inline void PutN(GenericStringBuffer >& stream, char c, size_t n) { 112 | std::memset(stream.stack_.Push(n), c, n * sizeof(c)); 113 | } 114 | 115 | RAPIDJSON_NAMESPACE_END 116 | 117 | #if defined(__clang__) 118 | RAPIDJSON_DIAG_POP 119 | #endif 120 | 121 | #endif // RAPIDJSON_STRINGBUFFER_H_ 122 | -------------------------------------------------------------------------------- /install/arch/PKGBUILD: -------------------------------------------------------------------------------- 1 | # Maintainer: nullobsi 2 | 3 | pkgname=pass-secrets-git 4 | pkgver=r61.62ad348 5 | pkgrel=1 6 | pkgdesc="Freedesktop secrets provider that uses pass as a backend" 7 | arch=('x86_64') 8 | url="https://github.com/nullobsi/pass-secrets" 9 | license=('GPL3') 10 | groups=() 11 | depends=('sdbus-cpp' 'pass') 12 | makedepends=('git' 'cmake') 13 | provides=("${pkgname%-git}" "org.freedesktop.secrets") 14 | conflicts=("${pkgname%-git}") 15 | source=('git+https://github.com/nullobsi/pass-secrets.git') 16 | md5sums=('SKIP') 17 | 18 | pkgver() { 19 | cd "$srcdir/${pkgname%-git}" 20 | printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)" 21 | } 22 | 23 | build() { 24 | cmake -B build -S "${pkgname%-git}" \ 25 | -DCMAKE_BUILD_TYPE='None' \ 26 | -DCMAKE_INSTALL_PREFIX='/usr' \ 27 | -Wno-dev 28 | make -C build 29 | } 30 | 31 | package() { 32 | make -C build DESTDIR="$pkgdir/" install 33 | } 34 | -------------------------------------------------------------------------------- /install/pass-secrets.service.in: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Pass SecretService 3 | 4 | [Service] 5 | Type=dbus 6 | BusName=org.freedesktop.secrets 7 | ExecStart=@CMAKE_INSTALL_PREFIX@/bin/pass-secrets 8 | 9 | [Install] 10 | WantedBy=default.target 11 | Alias=dbus-org.freedesktop.secrets.service -------------------------------------------------------------------------------- /install/si.nullob.pass-secrets.service.in: -------------------------------------------------------------------------------- 1 | [D-BUS Service] 2 | Name=org.freedesktop.secrets 3 | SystemdService=pass-secrets.service 4 | Exec=@CMAKE_INSTALL_PREFIX@/bin/pass-secrets 5 | -------------------------------------------------------------------------------- /interop/DocumentHelper.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by nullobsi on 2021/03/17. 3 | // 4 | 5 | #include "DocumentHelper.h" 6 | 7 | using namespace std; 8 | using namespace rapidjson; 9 | 10 | namespace DHelper { 11 | // documents 12 | void 13 | WriteDocument(const Document &d, 14 | ostream &f) { 15 | 16 | OStreamWrapper wrapper(f); 17 | Writer writer(wrapper); 18 | d.Accept(writer); 19 | writer.Flush(); 20 | } 21 | 22 | Document 23 | ReadDocument(istream &f) { 24 | IStreamWrapper wrapper(f); 25 | Document d; 26 | d.ParseStream(wrapper); 27 | return d; 28 | } 29 | 30 | 31 | Value 32 | SerializeAttrib(map &dict, 33 | MemoryPoolAllocator &alloc) { 34 | Value d; 35 | d.SetObject(); 36 | for (auto &entry : dict) { 37 | d.AddMember(GenericStringRef(entry.first.c_str()), entry.second, alloc); 38 | } 39 | return d; 40 | } 41 | 42 | map 43 | ReadAttrib(Value &d) { 44 | if (!d.IsObject()) { 45 | throw std::runtime_error("Invalid value!"); 46 | } 47 | 48 | map rtn; 49 | 50 | for (auto &entry : d.GetObject()) { 51 | rtn.insert({entry.name.GetString(), entry.value.GetString()}); 52 | } 53 | 54 | return rtn; 55 | } 56 | 57 | 58 | } -------------------------------------------------------------------------------- /interop/DocumentHelper.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by nullobsi on 2021/03/17. 3 | // 4 | 5 | #ifndef PASS_FDO_SECRETS_DOCUMENTHELPER_H 6 | #define PASS_FDO_SECRETS_DOCUMENTHELPER_H 7 | 8 | #include "rapidjson/document.h" 9 | #include "rapidjson/writer.h" 10 | #include "rapidjson/ostreamwrapper.h" 11 | #include "rapidjson/istreamwrapper.h" 12 | #include "iostream" 13 | #include "sdbus-c++/sdbus-c++.h" 14 | 15 | 16 | namespace DHelper { 17 | using namespace std; 18 | using namespace rapidjson; 19 | 20 | // documents 21 | void 22 | WriteDocument(const Document &d, 23 | ostream &f); 24 | 25 | Document 26 | ReadDocument(istream &f); 27 | 28 | 29 | Value 30 | SerializeAttrib(map &dict, 31 | MemoryPoolAllocator &alloc); 32 | 33 | map 34 | ReadAttrib(Value &d); 35 | } 36 | 37 | #endif //PASS_FDO_SECRETS_DOCUMENTHELPER_H 38 | -------------------------------------------------------------------------------- /interop/PassCollection.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by nullobsi on 2021/03/17. 3 | // 4 | 5 | #include 6 | #include 7 | #include "PassCollection.h" 8 | #include "DocumentHelper.h" 9 | #include "PassItem.h" 10 | #include "subprocess.h" 11 | #include "nanoid/nanoid.h" 12 | #include "PassStore.h" 13 | 14 | using namespace std; 15 | using namespace rapidjson; 16 | 17 | 18 | PassCollection::PassCollection(std::filesystem::path location_) : location(std::move(location_)), alias() { 19 | fstream docFile; 20 | docFile.open(location / "collection.json", ios::in); 21 | Document d = DHelper::ReadDocument(docFile); 22 | docFile.close(); 23 | 24 | if (d.HasParseError()) goto err; 25 | if (!d.IsObject()) goto err; 26 | if (!d.HasMember("label") || !d["label"].IsString()) goto err; 27 | if (!d.HasMember("created") || !d["created"].IsUint64()) goto err; 28 | if (!d.HasMember("id") || !d["id"].IsString()) goto err; 29 | 30 | label = d["label"].GetString(); 31 | created = d["created"].GetUint64(); 32 | id = d["id"].GetString(); 33 | if (d.HasMember("alias") && !d["alias"].IsNull()) { 34 | alias = d["alias"].GetString(); 35 | } 36 | 37 | 38 | for (auto &entry : filesystem::directory_iterator(location)) { 39 | if (!entry.is_directory()) continue; 40 | const auto &itemPath = entry.path(); 41 | if (!filesystem::exists(itemPath / "item.json")) continue; 42 | try { 43 | auto n = make_shared(itemPath); 44 | items.insert({n->getId(), move(n)}); 45 | } catch (std::exception &e) { 46 | cerr << "Error parsing item at " + itemPath.generic_string() + "!" << endl; 47 | } 48 | 49 | } 50 | 51 | 52 | return; 53 | 54 | 55 | err: 56 | throw std::runtime_error("Error parsing collection at " + location_.generic_string() + "!"); 57 | } 58 | 59 | PassCollection::PassCollection(filesystem::path &location_, 60 | std::string label_, 61 | std::string id_, 62 | int64_t created_, 63 | std::string alias_) : label(std::move(label_)), id(std::move(id_)), created(created_), 64 | location(location_), alias(std::move(alias_)) { 65 | 66 | } 67 | 68 | std::string 69 | PassCollection::getId() { 70 | return id; 71 | } 72 | 73 | std::string 74 | PassCollection::getLabel() { 75 | return label; 76 | } 77 | 78 | std::string 79 | PassCollection::getAlias() { 80 | return alias; 81 | } 82 | 83 | uint64_t 84 | PassCollection::getCreated() const { 85 | return created; 86 | } 87 | 88 | std::vector> 89 | PassCollection::getItems() { 90 | std::vector> r; 91 | for (const auto &entry : items) { 92 | r.push_back(entry.second); 93 | } 94 | return r; 95 | } 96 | 97 | std::vector 98 | PassCollection::searchItems(const map &attribs) { 99 | // TODO: maybe better way to search 100 | std::vector r; 101 | for (const auto &entry : items) { 102 | auto itemAttrib = entry.second->getAttrib(); 103 | bool match = true; 104 | for (const auto &attrib : attribs) { 105 | if (!itemAttrib.count(attrib.first) || itemAttrib[attrib.first] != attrib.second) { 106 | match = false; 107 | } 108 | } 109 | if (match) { 110 | r.push_back(entry.second->getId()); 111 | } 112 | } 113 | return r; 114 | } 115 | 116 | void 117 | PassCollection::Delete() { 118 | string path = (location).lexically_relative(location.parent_path().parent_path()).generic_string(); 119 | 120 | subprocess::command cmdline {PassStore::passLocation + " rm -rf " + path}; 121 | cmdline.run(); 122 | } 123 | 124 | std::shared_ptr 125 | PassCollection::CreateItem(uint8_t *data, 126 | size_t len, 127 | std::map attrib, 128 | std::string itemLabel, 129 | std::string type) { 130 | string itemId = nanoid::generate(); 131 | string path = (location / itemId / "secret").lexically_relative(location.parent_path().parent_path()).generic_string(); 132 | 133 | string datStr((char*)data, len); 134 | subprocess::command cmdline {PassStore::passLocation + " insert -mf " + path}; 135 | 136 | (cmdline < datStr).run(); 137 | 138 | Document d; 139 | auto itemCreated = (uint64_t)time(nullptr); 140 | d.SetObject(); 141 | d.AddMember("label", itemLabel, d.GetAllocator()); 142 | d.AddMember("created", itemCreated, d.GetAllocator()); 143 | d.AddMember("id", itemId, d.GetAllocator()); 144 | d.AddMember("type", type, d.GetAllocator()); 145 | d.AddMember("attrib", DHelper::SerializeAttrib(attrib, d.GetAllocator()), d.GetAllocator()); 146 | d.AddMember("modified", itemCreated, d.GetAllocator()); 147 | 148 | fstream f; 149 | f.open(location / itemId / "item.json", ios::trunc | ios::out); 150 | DHelper::WriteDocument(d, f); 151 | f.close(); 152 | auto final = make_shared(location / itemId, std::move(itemLabel), itemCreated, std::move(itemId), std::move(attrib), std::move(type), data, len, itemCreated); 153 | items.insert({final->getId(), final}); 154 | return final; 155 | } 156 | 157 | void 158 | PassCollection::updateMetadata() { 159 | Document d; 160 | d.SetObject(); 161 | d.AddMember("label", label, d.GetAllocator()); 162 | d.AddMember("created", created, d.GetAllocator()); 163 | d.AddMember("id", id, d.GetAllocator()); 164 | d.AddMember("alias", alias, d.GetAllocator()); 165 | 166 | fstream f; 167 | f.open(location / "collection.json", ios::trunc | ios::out); 168 | DHelper::WriteDocument(d, f); 169 | f.close(); 170 | } 171 | 172 | void 173 | PassCollection::setLabel(std::string n) { 174 | label = move(n); 175 | } 176 | 177 | void 178 | PassCollection::setAlias(std::string n) { 179 | alias = move(n); 180 | } 181 | 182 | void 183 | PassCollection::RemoveItem(std::string id) { 184 | items.extract(id); 185 | } 186 | -------------------------------------------------------------------------------- /interop/PassCollection.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by nullobsi on 2021/03/17. 3 | // 4 | 5 | #ifndef PASS_FDO_SECRETS_PASSCOLLECTION_H 6 | #define PASS_FDO_SECRETS_PASSCOLLECTION_H 7 | 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | class PassItem; 14 | 15 | class PassCollection { 16 | public: 17 | explicit PassCollection(std::filesystem::path location_); 18 | 19 | PassCollection(std::filesystem::path &location_, 20 | std::string label_, 21 | std::string id_, 22 | int64_t created_, 23 | std::string alias_); 24 | 25 | std::string 26 | getId(); 27 | 28 | std::string 29 | getLabel(); 30 | 31 | std::string 32 | getAlias(); 33 | 34 | uint64_t 35 | getCreated() const; 36 | 37 | std::vector> 38 | getItems(); 39 | 40 | std::vector 41 | searchItems(const std::map &attrib); 42 | 43 | void 44 | Delete(); 45 | 46 | std::shared_ptr 47 | CreateItem(uint8_t *data, size_t len, std::map attrib, std::string itemLabel, std::string type); 48 | 49 | void 50 | updateMetadata(); 51 | 52 | void 53 | setLabel(std::string n); 54 | 55 | void 56 | setAlias(std::string n); 57 | 58 | void 59 | RemoveItem(std::string id); 60 | 61 | private: 62 | std::filesystem::path location; 63 | std::string label; 64 | uint64_t created; 65 | std::string id; 66 | std::string alias; 67 | 68 | std::map> items; 69 | }; 70 | 71 | 72 | #endif //PASS_FDO_SECRETS_PASSCOLLECTION_H 73 | -------------------------------------------------------------------------------- /interop/PassItem.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by nullobsi on 2021/03/17. 3 | // 4 | 5 | #include "PassItem.h" 6 | 7 | #include 8 | #include 9 | #include 10 | #include "DocumentHelper.h" 11 | #include "subprocess.h" 12 | #include "iostream" 13 | #include "PassStore.h" 14 | 15 | using namespace std; 16 | using namespace rapidjson; 17 | using namespace subprocess::literals; 18 | 19 | PassItem::PassItem(std::filesystem::path location_) : location(move(location_)) { 20 | fstream docFile; 21 | docFile.open(location / "item.json", ios::in); 22 | Document d = DHelper::ReadDocument(docFile); 23 | docFile.close(); 24 | 25 | if (d.HasParseError()) goto err; 26 | if (!d.IsObject()) goto err; 27 | if (!d.HasMember("label") || !d["label"].IsString()) goto err; 28 | if (!d.HasMember("created") || !d["created"].IsUint64()) goto err; 29 | if (!d.HasMember("id") || !d["id"].IsString()) goto err; 30 | if (!d.HasMember("type") || !d["type"].IsString()) goto err; 31 | if (!d.HasMember("attrib") || !d["attrib"].IsObject()) goto err; 32 | if (!d.HasMember("modified") || !d["modified"].IsUint64()) goto err; 33 | 34 | label = d["label"].GetString(); 35 | created = d["created"].GetUint64(); 36 | modified = d["modified"].GetUint64(); 37 | id = d["id"].GetString(); 38 | type = d["type"].GetString(); 39 | try { 40 | attrib = move(DHelper::ReadAttrib(d["attrib"])); 41 | } catch (std::exception &e) { 42 | goto err; 43 | } 44 | 45 | 46 | return; 47 | 48 | 49 | err: 50 | throw std::runtime_error("Error parsing item at " + location_.generic_string() + "!"); 51 | } 52 | 53 | uint64_t 54 | PassItem::getCreated() { 55 | return created; 56 | } 57 | 58 | std::map 59 | PassItem::getAttrib() { 60 | return attrib; 61 | } 62 | 63 | bool 64 | PassItem::hasAttrib(const std::string &key, 65 | const std::string &val) { 66 | if (attrib.count(key)) { 67 | if (attrib[key] == val) return true; 68 | } 69 | return false; 70 | } 71 | 72 | std::string 73 | PassItem::getLabel() { 74 | return label; 75 | } 76 | 77 | std::string 78 | PassItem::getId() { 79 | return id; 80 | } 81 | 82 | std::string 83 | PassItem::getType() { 84 | return type; 85 | } 86 | 87 | uint8_t * 88 | PassItem::getSecret() { 89 | return secret; 90 | } 91 | 92 | size_t 93 | PassItem::getSecretLength() { 94 | return secretLength; 95 | } 96 | 97 | 98 | #define BUF_SIZE 1024 99 | 100 | bool 101 | PassItem::unlock() { 102 | string path = (location / "secret").lexically_relative(location.parent_path().parent_path().parent_path()) 103 | .generic_string(); 104 | string out; 105 | subprocess::command cmdline {PassStore::passLocation + " show \"" + path + "\""}; 106 | (cmdline > out).run(); 107 | 108 | secretLength = out.length(); 109 | secret = static_cast(malloc(secretLength)); 110 | memcpy(secret, out.c_str(), secretLength); 111 | 112 | return true; 113 | } 114 | 115 | bool 116 | PassItem::isUnlocked() { 117 | return secret != nullptr; 118 | } 119 | 120 | void 121 | PassItem::lock() { 122 | if (isUnlocked()) { 123 | memset(secret, 0, secretLength); 124 | free(secret); 125 | secret = nullptr; 126 | secretLength = 0; 127 | } 128 | } 129 | 130 | PassItem::~PassItem() { 131 | lock(); 132 | } 133 | 134 | PassItem::PassItem(std::filesystem::path location_, 135 | std::string label_, 136 | uint64_t created_, 137 | std::string id_, 138 | std::map attrib_, 139 | std::string type_, 140 | uint8_t *secret_, 141 | size_t secretLen_, 142 | uint64_t modified_) : location(move(location_)), label(move(label_)), created(created_), id(move(id_)), attrib(move(attrib_)), type(move(type_)), secret(secret_), secretLength(secretLen_), modified(modified_){ 143 | 144 | } 145 | 146 | void 147 | PassItem::updateMetadata() { 148 | Document d; 149 | d.SetObject(); 150 | d.AddMember("label", label, d.GetAllocator()); 151 | d.AddMember("created", created, d.GetAllocator()); 152 | d.AddMember("modified", modified, d.GetAllocator()); 153 | d.AddMember("id", id, d.GetAllocator()); 154 | d.AddMember("type", type, d.GetAllocator()); 155 | d.AddMember("attrib", DHelper::SerializeAttrib(attrib, d.GetAllocator()), d.GetAllocator()); 156 | 157 | fstream f; 158 | f.open(location / "item.json", ios::out | ios::trunc); 159 | DHelper::WriteDocument(d, f); 160 | f.close(); 161 | } 162 | 163 | void 164 | PassItem::setLabel(std::string n) { 165 | modified = (uint64_t)time(nullptr); 166 | label = move(n); 167 | } 168 | 169 | void 170 | PassItem::setAttrib(std::map n) { 171 | modified = (uint64_t)time(nullptr); 172 | attrib = move(n); 173 | } 174 | 175 | void 176 | PassItem::setType(std::string n) { 177 | modified = (uint64_t)time(nullptr); 178 | type = move(n); 179 | } 180 | 181 | void 182 | PassItem::setSecret(uint8_t *data, 183 | size_t n) { 184 | modified = (uint64_t)time(nullptr); 185 | secret = data; 186 | secretLength = n; 187 | string path = (location / "secret").lexically_relative(location.parent_path().parent_path().parent_path()).generic_string(); 188 | string datStr((char*)data, n); 189 | subprocess::command cmdline {PassStore::passLocation + " insert -mf " + path}; 190 | 191 | (cmdline < datStr).run(); 192 | } 193 | 194 | void 195 | PassItem::Delete() { 196 | string path = (location).lexically_relative(location.parent_path().parent_path().parent_path()).generic_string(); 197 | 198 | subprocess::command cmdline {PassStore::passLocation + " rm -rf " + path}; 199 | cmdline.run(); 200 | } 201 | 202 | uint64_t 203 | PassItem::getModified() { 204 | return modified; 205 | } 206 | 207 | -------------------------------------------------------------------------------- /interop/PassItem.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by nullobsi on 2021/03/17. 3 | // 4 | 5 | #ifndef PASS_FDO_SECRETS_PASSITEM_H 6 | #define PASS_FDO_SECRETS_PASSITEM_H 7 | 8 | #include 9 | #include 10 | 11 | class PassItem { 12 | public: 13 | explicit PassItem(std::filesystem::path location_); 14 | PassItem(std::filesystem::path location_, std::string label_, uint64_t created_, std::string id_, std::map attrib_, std::string type_, uint8_t *secret_, size_t secretLen_, uint64_t modified_); 15 | 16 | ~PassItem(); 17 | 18 | uint64_t 19 | getCreated(); 20 | 21 | uint64_t 22 | getModified(); 23 | 24 | std::map 25 | getAttrib(); 26 | 27 | std::string 28 | getLabel(); 29 | 30 | std::string 31 | getId(); 32 | 33 | std::string 34 | getType(); 35 | 36 | bool 37 | hasAttrib(const std::string &key, 38 | const std::string &val); 39 | 40 | bool 41 | isUnlocked(); 42 | 43 | bool 44 | unlock(); 45 | 46 | void 47 | lock(); 48 | 49 | size_t 50 | getSecretLength(); 51 | 52 | uint8_t * 53 | getSecret(); 54 | 55 | void 56 | setLabel(std::string n); 57 | 58 | void 59 | setAttrib(std::map n); 60 | 61 | void 62 | setType(std::string n); 63 | 64 | void 65 | setSecret(uint8_t *data, size_t n); 66 | 67 | void 68 | updateMetadata(); 69 | 70 | void 71 | Delete(); 72 | 73 | 74 | private: 75 | std::filesystem::path location; 76 | 77 | // info 78 | std::map attrib; 79 | uint64_t created; 80 | uint64_t modified; 81 | std::string label; 82 | std::string id; 83 | std::string type; 84 | 85 | size_t secretLength = 0; 86 | uint8_t *secret = nullptr; 87 | 88 | }; 89 | 90 | 91 | #endif //PASS_FDO_SECRETS_PASSITEM_H 92 | -------------------------------------------------------------------------------- /interop/PassStore.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by nullobsi on 2021/03/17. 3 | // 4 | 5 | #include "PassStore.h" 6 | #include "DocumentHelper.h" 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | string PassStore::passLocation; 15 | 16 | PassStore::PassStore() { 17 | auto storeLoc = getenv("PASSWORD_STORE_DIR"); 18 | auto homeDir = getenv("HOME"); 19 | if (storeLoc) { 20 | storePrefix = string(storeLoc); 21 | storePrefix /= "secretservice"; 22 | } else if (homeDir) { 23 | storePrefix = string(homeDir); 24 | storePrefix /= ".password-store/secretservice"; 25 | } else { 26 | throw runtime_error("Could not find password store! Please set $HOME or $PASSWORD_STORE_DIR"); 27 | } 28 | 29 | if (!filesystem::exists(storePrefix)) { 30 | try { 31 | filesystem::create_directory(storePrefix); 32 | } catch (std::filesystem::filesystem_error &e) { 33 | throw runtime_error("Could not create directory " + storePrefix.string()); 34 | } 35 | } 36 | 37 | bool hasDefault = false; 38 | 39 | for (auto &entry : filesystem::directory_iterator(storePrefix)) { 40 | if (entry.is_directory()) { 41 | if (filesystem::exists(entry.path() / "collection.json")) { 42 | try { 43 | auto collection = make_shared(entry.path()); 44 | collections.insert({collection->getId(), collection}); 45 | cout << "Loaded collection " + entry.path().generic_string() << endl; 46 | if (collection->getAlias() == "default") hasDefault = true; 47 | } catch (std::runtime_error &e) { 48 | cerr << e.what() << endl; 49 | } 50 | } 51 | } 52 | } 53 | if (!hasDefault) createDefaultCollection(); 54 | 55 | if (passLocation.empty()) { 56 | namespace fs = std::filesystem; 57 | stringstream path = stringstream(getenv("PATH")); 58 | vector pathEntries; 59 | string token; 60 | while (getline(path, token, ':')) { 61 | pathEntries.push_back(token); 62 | } 63 | for (const auto &dirName : pathEntries) { 64 | // Handle any potential errors in filesystem access. 65 | try { 66 | fs::directory_iterator i(dirName); 67 | for (const auto &file : i) { 68 | if (file.is_regular_file() && file.path().filename() == "pass") { 69 | std::cout << "Found pass at " + file.path().string() << std::endl; 70 | passLocation = file.path().string(); 71 | goto finish; 72 | } 73 | } 74 | } catch (std::exception &error) { 75 | cerr << "Error found while accessing " << dirName << " in path:" << endl; 76 | // std::filesystem_error should include details in 77 | // what()... 78 | cerr << error.what() << endl; 79 | continue; 80 | } 81 | } 82 | throw std::runtime_error("Pass not found in path!"); 83 | finish: 84 | return; 85 | } 86 | } 87 | 88 | void 89 | PassStore::createDefaultCollection() { 90 | CreateCollection("Default Keyring", "default"); 91 | } 92 | 93 | std::shared_ptr 94 | PassStore::CreateCollection(const std::string &label, 95 | const std::string &alias) { 96 | using namespace rapidjson; 97 | Document d; 98 | d.SetObject(); 99 | 100 | // label, created date, object path ID 101 | auto created = std::time(nullptr); 102 | auto id = nanoid::generate(); 103 | 104 | d.AddMember("label", label, d.GetAllocator()); 105 | d.AddMember("created", created, d.GetAllocator()); 106 | d.AddMember("id", id, d.GetAllocator()); 107 | d.AddMember("alias", alias, d.GetAllocator()); 108 | 109 | filesystem::path location = storePrefix / id; 110 | if (!filesystem::exists(location)) { 111 | filesystem::create_directory(location); 112 | } 113 | fstream metadataFile; 114 | metadataFile.open(location / "collection.json", ios::out | ios::trunc); 115 | DHelper::WriteDocument(d, metadataFile); 116 | metadataFile.close(); 117 | 118 | auto c = make_shared(location, label, id, created, alias); 119 | collections.insert({id, c}); 120 | return c; 121 | } 122 | 123 | std::vector> 124 | PassStore::GetCollections() { 125 | vector> rtn; 126 | for (const auto &entry : collections) { 127 | rtn.push_back(entry.second); 128 | } 129 | 130 | return rtn; 131 | } 132 | 133 | 134 | 135 | -------------------------------------------------------------------------------- /interop/PassStore.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by nullobsi on 2021/03/17. 3 | // 4 | 5 | #ifndef PASS_FDO_SECRETS_PASSSTORE_H 6 | #define PASS_FDO_SECRETS_PASSSTORE_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include "PassCollection.h" 15 | 16 | class PassStore { 17 | public: 18 | PassStore(); 19 | 20 | std::shared_ptr 21 | CreateCollection(const std::string &label, 22 | const std::string &alias); 23 | 24 | std::vector> 25 | GetCollections(); 26 | 27 | static std::string passLocation; 28 | 29 | private: 30 | void 31 | createDefaultCollection(); 32 | 33 | // password store location 34 | std::filesystem::path storePrefix; 35 | 36 | // collections 37 | std::map> collections; 38 | 39 | 40 | }; 41 | 42 | 43 | #endif //PASS_FDO_SECRETS_PASSSTORE_H 44 | -------------------------------------------------------------------------------- /introspection/collection.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /introspection/item.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /introspection/prompt.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /introspection/secrets.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /introspection/session.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "impl/SecretService.h" 7 | 8 | int 9 | main() { 10 | 11 | std::unique_ptr conn; 12 | try { 13 | conn = sdbus::createSessionBusConnection(); 14 | } catch (std::runtime_error &e) { 15 | std::cerr << "There was an error creating DBus connection." << std::endl; 16 | std::cerr << "Error: " << e.what() << std::endl; 17 | return 1; 18 | } 19 | conn->requestName("org.freedesktop.secrets"); 20 | 21 | std::shared_ptr service; 22 | try { 23 | service = std::make_shared(*conn, "/org/freedesktop/secrets"); 24 | } catch(sdbus::Error &e) { 25 | std::cerr << "There was an error registering to DBus." << std::endl; 26 | std::cerr << "Error: " << e.what() << std::endl; 27 | return 1; 28 | } 29 | 30 | service->InitCollections(); 31 | while (true) { 32 | if (!conn->processPendingRequest()) { 33 | std::cerr << "There was an error processing DBus events!" << std::endl; 34 | return 1; 35 | } 36 | service->DiscardObjects(); 37 | 38 | auto dat = conn->getEventLoopPollData(); 39 | struct pollfd polling[] = {{ 40 | dat.fd, dat.events, 0 41 | }}; 42 | auto timeout = dat.timeout_usec == (uint64_t)-1 ? (uint64_t)-1 : (dat.timeout_usec + 999) / 1000; 43 | auto res = poll(polling, 1, timeout); 44 | if (res < 1 && errno == EINTR) { 45 | std::cerr << "Got interrupt, exiting..." << std::endl; 46 | return 0; 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /nanoid_cpp/.gitignore: -------------------------------------------------------------------------------- 1 | # ----- C++ ----- 2 | # Prerequisites 3 | *.d 4 | 5 | # Compiled Object files 6 | *.slo 7 | *.lo 8 | *.o 9 | *.obj 10 | 11 | # Precompiled Headers 12 | *.gch 13 | *.pch 14 | 15 | # Compiled Dynamic libraries 16 | *.so 17 | *.dylib 18 | *.dll 19 | 20 | # Fortran module files 21 | *.mod 22 | *.smod 23 | 24 | # Compiled Static libraries 25 | *.lai 26 | *.la 27 | *.a 28 | *.lib 29 | 30 | # Executables 31 | *.exe 32 | *.out 33 | *.app 34 | 35 | # ----- CMake ----- 36 | CMakeLists.txt.user 37 | CMakeCache.txt 38 | CMakeFiles 39 | CMakeScripts 40 | Testing 41 | Makefile 42 | cmake_install.cmake 43 | install_manifest.txt 44 | compile_commands.json 45 | CTestTestfile.cmake 46 | _deps 47 | 48 | # ----- Lua ----- 49 | # Compiled Lua sources 50 | luac.out 51 | 52 | # luarocks build files 53 | *.src.rock 54 | *.zip 55 | *.tar.gz 56 | 57 | # Object files 58 | *.o 59 | *.os 60 | *.ko 61 | *.obj 62 | *.elf 63 | 64 | # Precompiled Headers 65 | *.gch 66 | *.pch 67 | 68 | # Libraries 69 | *.lib 70 | *.a 71 | *.la 72 | *.lo 73 | *.def 74 | *.exp 75 | 76 | # Shared objects (inc. Windows DLLs) 77 | *.dll 78 | *.so 79 | *.so.* 80 | *.dylib 81 | 82 | # Executables 83 | *.exe 84 | *.out 85 | *.app 86 | *.i*86 87 | *.x86_64 88 | *.hex 89 | 90 | # ----- VS CODE ----- 91 | 92 | .vscode/ 93 | .vscode/* 94 | !.vscode/settings.json 95 | !.vscode/tasks.json 96 | !.vscode/launch.json 97 | !.vscode/extensions.json 98 | *.code-workspace 99 | 100 | # Local History for Visual Studio Code 101 | .history/ 102 | 103 | # ----- Visual Studio ----- 104 | ## Ignore Visual Studio temporary files, build results, and 105 | ## files generated by popular Visual Studio add-ons. 106 | ## 107 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 108 | 109 | # User-specific files 110 | *.rsuser 111 | *.suo 112 | *.user 113 | *.userosscache 114 | *.sln.docstates 115 | 116 | # User-specific files (MonoDevelop/Xamarin Studio) 117 | *.userprefs 118 | 119 | # Mono auto generated files 120 | mono_crash.* 121 | 122 | # Build results 123 | [Dd]ebug/ 124 | [Dd]ebugPublic/ 125 | [Rr]elease/ 126 | [Rr]eleases/ 127 | x64/ 128 | x86/ 129 | [Aa][Rr][Mm]/ 130 | [Aa][Rr][Mm]64/ 131 | bld/ 132 | [Bb]in/ 133 | [Oo]bj/ 134 | [Ll]og/ 135 | [Ll]ogs/ 136 | [Oo]ut/ 137 | 138 | # Visual Studio 2015/2017 cache/options directory 139 | .vs/ 140 | # Uncomment if you have tasks that create the project's static files in wwwroot 141 | #wwwroot/ 142 | 143 | # Visual Studio 2017 auto generated files 144 | Generated\ Files/ 145 | 146 | # MSTest test Results 147 | [Tt]est[Rr]esult*/ 148 | [Bb]uild[Ll]og.* 149 | 150 | # NUnit 151 | *.VisualState.xml 152 | TestResult.xml 153 | nunit-*.xml 154 | 155 | # Build Results of an ATL Project 156 | [Dd]ebugPS/ 157 | [Rr]eleasePS/ 158 | dlldata.c 159 | 160 | # Benchmark Results 161 | BenchmarkDotNet.Artifacts/ 162 | 163 | # .NET Core 164 | project.lock.json 165 | project.fragment.lock.json 166 | artifacts/ 167 | 168 | # StyleCop 169 | StyleCopReport.xml 170 | 171 | # Files built by Visual Studio 172 | *_i.c 173 | *_p.c 174 | *_h.h 175 | *.ilk 176 | *.meta 177 | *.obj 178 | *.iobj 179 | *.pch 180 | *.pdb 181 | *.ipdb 182 | *.pgc 183 | *.pgd 184 | *.rsp 185 | *.sbr 186 | *.tlb 187 | *.tli 188 | *.tlh 189 | *.tmp 190 | *.tmp_proj 191 | *_wpftmp.csproj 192 | *.log 193 | *.vspscc 194 | *.vssscc 195 | .builds 196 | *.pidb 197 | *.svclog 198 | *.scc 199 | 200 | # Chutzpah Test files 201 | _Chutzpah* 202 | 203 | # Visual C++ cache files 204 | ipch/ 205 | *.aps 206 | *.ncb 207 | *.opendb 208 | *.opensdf 209 | *.sdf 210 | *.cachefile 211 | *.VC.db 212 | *.VC.VC.opendb 213 | 214 | # Visual Studio profiler 215 | *.psess 216 | *.vsp 217 | *.vspx 218 | *.sap 219 | 220 | # Visual Studio Trace Files 221 | *.e2e 222 | 223 | # TFS 2012 Local Workspace 224 | $tf/ 225 | 226 | # Guidance Automation Toolkit 227 | *.gpState 228 | 229 | # ReSharper is a .NET coding add-in 230 | _ReSharper*/ 231 | *.[Rr]e[Ss]harper 232 | *.DotSettings.user 233 | 234 | # JustCode is a .NET coding add-in 235 | .JustCode 236 | 237 | # TeamCity is a build add-in 238 | _TeamCity* 239 | 240 | # DotCover is a Code Coverage Tool 241 | *.dotCover 242 | 243 | # AxoCover is a Code Coverage Tool 244 | .axoCover/* 245 | !.axoCover/settings.json 246 | 247 | # Visual Studio code coverage results 248 | *.coverage 249 | *.coveragexml 250 | 251 | # NCrunch 252 | _NCrunch_* 253 | .*crunch*.local.xml 254 | nCrunchTemp_* 255 | 256 | # MightyMoose 257 | *.mm.* 258 | AutoTest.Net/ 259 | 260 | # Web workbench (sass) 261 | .sass-cache/ 262 | 263 | # Installshield output folder 264 | [Ee]xpress/ 265 | 266 | # DocProject is a documentation generator add-in 267 | DocProject/buildhelp/ 268 | DocProject/Help/*.HxT 269 | DocProject/Help/*.HxC 270 | DocProject/Help/*.hhc 271 | DocProject/Help/*.hhk 272 | DocProject/Help/*.hhp 273 | DocProject/Help/Html2 274 | DocProject/Help/html 275 | 276 | # Click-Once directory 277 | publish/ 278 | 279 | # Publish Web Output 280 | *.[Pp]ublish.xml 281 | *.azurePubxml 282 | # Note: Comment the next line if you want to checkin your web deploy settings, 283 | # but database connection strings (with potential passwords) will be unencrypted 284 | *.pubxml 285 | *.publishproj 286 | 287 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 288 | # checkin your Azure Web App publish settings, but sensitive information contained 289 | # in these scripts will be unencrypted 290 | PublishScripts/ 291 | 292 | # NuGet Packages 293 | *.nupkg 294 | # NuGet Symbol Packages 295 | *.snupkg 296 | # The packages folder can be ignored because of Package Restore 297 | **/[Pp]ackages/* 298 | # except build/, which is used as an MSBuild target. 299 | !**/[Pp]ackages/build/ 300 | # Uncomment if necessary however generally it will be regenerated when needed 301 | #!**/[Pp]ackages/repositories.config 302 | # NuGet v3's project.json files produces more ignorable files 303 | *.nuget.props 304 | *.nuget.targets 305 | 306 | # Microsoft Azure Build Output 307 | csx/ 308 | *.build.csdef 309 | 310 | # Microsoft Azure Emulator 311 | ecf/ 312 | rcf/ 313 | 314 | # Windows Store app package directories and files 315 | AppPackages/ 316 | BundleArtifacts/ 317 | Package.StoreAssociation.xml 318 | _pkginfo.txt 319 | *.appx 320 | *.appxbundle 321 | *.appxupload 322 | 323 | # Visual Studio cache files 324 | # files ending in .cache can be ignored 325 | *.[Cc]ache 326 | # but keep track of directories ending in .cache 327 | !?*.[Cc]ache/ 328 | 329 | # Others 330 | ClientBin/ 331 | ~$* 332 | *~ 333 | *.dbmdl 334 | *.dbproj.schemaview 335 | *.jfm 336 | *.pfx 337 | *.publishsettings 338 | orleans.codegen.cs 339 | 340 | # Including strong name files can present a security risk 341 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 342 | #*.snk 343 | 344 | # Since there are multiple workflows, uncomment next line to ignore bower_components 345 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 346 | #bower_components/ 347 | 348 | # RIA/Silverlight projects 349 | Generated_Code/ 350 | 351 | # Backup & report files from converting an old project file 352 | # to a newer Visual Studio version. Backup files are not needed, 353 | # because we have git ;-) 354 | _UpgradeReport_Files/ 355 | Backup*/ 356 | UpgradeLog*.XML 357 | UpgradeLog*.htm 358 | ServiceFabricBackup/ 359 | *.rptproj.bak 360 | 361 | # SQL Server files 362 | *.mdf 363 | *.ldf 364 | *.ndf 365 | 366 | # Business Intelligence projects 367 | *.rdl.data 368 | *.bim.layout 369 | *.bim_*.settings 370 | *.rptproj.rsuser 371 | *- [Bb]ackup.rdl 372 | *- [Bb]ackup ([0-9]).rdl 373 | *- [Bb]ackup ([0-9][0-9]).rdl 374 | 375 | # Microsoft Fakes 376 | FakesAssemblies/ 377 | 378 | # GhostDoc plugin setting file 379 | *.GhostDoc.xml 380 | 381 | # Node.js Tools for Visual Studio 382 | .ntvs_analysis.dat 383 | node_modules/ 384 | 385 | # Visual Studio 6 build log 386 | *.plg 387 | 388 | # Visual Studio 6 workspace options file 389 | *.opt 390 | 391 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 392 | *.vbw 393 | 394 | # Visual Studio LightSwitch build output 395 | **/*.HTMLClient/GeneratedArtifacts 396 | **/*.DesktopClient/GeneratedArtifacts 397 | **/*.DesktopClient/ModelManifest.xml 398 | **/*.Server/GeneratedArtifacts 399 | **/*.Server/ModelManifest.xml 400 | _Pvt_Extensions 401 | 402 | # Paket dependency manager 403 | .paket/paket.exe 404 | paket-files/ 405 | 406 | # FAKE - F# Make 407 | .fake/ 408 | 409 | # CodeRush personal settings 410 | .cr/personal 411 | 412 | # Python Tools for Visual Studio (PTVS) 413 | __pycache__/ 414 | *.pyc 415 | 416 | # Cake - Uncomment if you are using it 417 | # tools/** 418 | # !tools/packages.config 419 | 420 | # Tabs Studio 421 | *.tss 422 | 423 | # Telerik's JustMock configuration file 424 | *.jmconfig 425 | 426 | # BizTalk build output 427 | *.btp.cs 428 | *.btm.cs 429 | *.odx.cs 430 | *.xsd.cs 431 | 432 | # OpenCover UI analysis results 433 | OpenCover/ 434 | 435 | # Azure Stream Analytics local run output 436 | ASALocalRun/ 437 | 438 | # MSBuild Binary and Structured Log 439 | *.binlog 440 | 441 | # NVidia Nsight GPU debugger configuration file 442 | *.nvuser 443 | 444 | # MFractors (Xamarin productivity tool) working folder 445 | .mfractor/ 446 | 447 | # Local History for Visual Studio 448 | .localhistory/ 449 | 450 | # BeatPulse healthcheck temp database 451 | healthchecksdb 452 | 453 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 454 | MigrationBackup/ 455 | 456 | # Ionide (cross platform F# VS Code tools) working folder 457 | .ionide/ 458 | -------------------------------------------------------------------------------- /nanoid_cpp/.travis.yml: -------------------------------------------------------------------------------- 1 | language: cpp 2 | sudo: required 3 | dist: bionic 4 | compiler: 5 | - gcc 6 | os: 7 | - linux 8 | 9 | branches: 10 | only: 11 | - master 12 | 13 | install: 14 | - DEPS_DIR="${TRAVIS_BUILD_DIR}/deps" 15 | - mkdir ${DEPS_DIR} && cd ${DEPS_DIR} 16 | - travis_retry wget --no-check-certificate https://cmake.org/files/v3.18/cmake-3.18.0-rc1-Linux-x86_64.tar.gz 17 | # this is optional, but useful: 18 | # do a quick md5 check to ensure that the archive we downloaded did not get compromised 19 | - echo "33b07e7e255555fa3bf64ae591b24e4f *cmake-3.18.0-rc1-Linux-x86_64.tar.gz" > cmake_md5.txt 20 | - md5sum -c cmake_md5.txt 21 | - tar -xvf cmake-3.18.0-rc1-Linux-x86_64.tar.gz > /dev/null 22 | - mv cmake-3.18.0-rc1-Linux-x86_64 cmake-install 23 | - PATH=${DEPS_DIR}/cmake-install:${DEPS_DIR}/cmake-install/bin:$PATH 24 | - cd ${TRAVIS_BUILD_DIR} 25 | 26 | before_script: 27 | - mkdir build 28 | - cd build 29 | - cmake .. 30 | 31 | script: 32 | - make 33 | - make test -------------------------------------------------------------------------------- /nanoid_cpp/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | project (nanoid_cpp 3 | VERSION 2.1.0 4 | ) 5 | set(CMAKE_CXX_STANDARD 11) 6 | set(THREADS_PREFER_PTHREAD_FLAG ON) 7 | find_package(Threads REQUIRED) 8 | 9 | #add_subdirectory(vendor/catch2) 10 | 11 | file(GLOB_RECURSE NANOID_SRC_FILES src/*.cpp) 12 | file(GLOB_RECURSE NANOID_INC_FILES inc/*.h) 13 | 14 | add_library(nanoid ${NANOID_SRC_FILES}) 15 | target_link_libraries(nanoid Threads::Threads) 16 | #target_compile_options(nanoid PRIVATE 17 | # $<$:/W4> 18 | # $<$>:-Wall -Wextra -pedantic> 19 | #) 20 | 21 | ############################################# 22 | # Unit tests 23 | 24 | #enable_testing() 25 | #add_executable(nanoid_tests tests/unit_tests.cpp) 26 | 27 | #target_link_libraries(nanoid_tests 28 | # nanoid 29 | # Catch2::Test 30 | #) 31 | 32 | #add_test(test_all nanoid_tests) 33 | -------------------------------------------------------------------------------- /nanoid_cpp/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Mykola Morozov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /nanoid_cpp/README.md: -------------------------------------------------------------------------------- 1 | # nanoid-cpp 2 | [![Build Status](https://travis-ci.org/mcmikecreations/nanoid_cpp.svg?branch=master)](https://travis-ci.org/mcmikecreations/nanoid_cpp) 3 | [![License](https://img.shields.io/badge/license-MIT%20License-blue.svg)](LICENSE) 4 | 5 | A tiny, URL-friendly, unique string ID generator for C++, implementation of [ai's](https://github.com/ai) [nanoid](https://github.com/ai/nanoid)! 6 | 7 | **Safe.** It uses `mt19937`, a strong random generator with a seed from `random_device`. 8 | 9 | **Compact.** It uses more symbols than UUID (`A-Za-z0-9_-`) 10 | and has the same number of unique options in just 22 symbols instead of 36. 11 | 12 | **Fast.** Nanoid is as fast as UUID but can be used in URLs. 13 | 14 | ## Install 15 | 16 | Install with cmake: 17 | 18 | 1. Copy git repo to your destination 19 | 2. Use `add_subdirectory` and `target_link_libraries` to add to your project. 20 | 3. Or use `cmake` and `make` to build the project and use it as a library. 21 | 22 | ## Usage 23 | 24 | ### Normal 25 | 26 | The default method uses URL-friendly symbols (`A-Za-z0-9_-`) and returns an ID 27 | with 21 characters (to have a collision probability similar to UUID v4). 28 | 29 | ```cpp 30 | std::string id = nanoid::generate(); 31 | //id := "Uakgb_J5m9g-0JDMbcJqLJ" 32 | ``` 33 | 34 | Symbols `-,.()` are not encoded in the URL. If used at the end of a link 35 | they could be identified as a punctuation symbol. 36 | 37 | If you want to reduce ID length (and increase collisions probability), 38 | you can pass the size as an argument: 39 | 40 | ```cpp 41 | std::string id = nanoid::generate(10); 42 | //id := "IRFa-VaY2b" 43 | ``` 44 | 45 | ### Async 46 | 47 | The async method can be used to simplify writing of asynchronous code. 48 | 49 | ```cpp 50 | auto id_fut = nanoid::generate_async(); 51 | //unrelated code here 52 | std::string id = id_fut.get(); 53 | //id := "Uakgb_J5m9g-0JDMbcJqLJ" 54 | ``` 55 | 56 | ### Custom Alphabet or Length 57 | 58 | If you want to change the ID's alphabet or length 59 | you can pass alphabet and size. 60 | 61 | ```cpp 62 | std::string id = nanoid::generate("1234567890abcdef", 10); 63 | //id := "4f90d13a42" 64 | ``` 65 | 66 | Alphabet must contain 256 symbols or less. 67 | Otherwise, the generator will not be secure. 68 | 69 | 70 | ### Custom Random Bytes Generator 71 | 72 | You can replace the default safe random generator using the `nanoid::crypto_random_base` or `nanoid::crypto_random` class. 73 | For instance, to use a seed-based generator. 74 | 75 | ```cpp 76 | auto random = nanoid::crypto_random(10); 77 | auto id = nanoid::generate(random, "abcdef", 10); 78 | //id := "fbaefaadeb" 79 | ``` 80 | 81 | ## Credits 82 | 83 | - [ai](https://github.com/ai) - [nanoid](https://github.com/ai/nanoid) 84 | - [codeyu](https://github.com/codeyu) - [nanoid-net](https://github.com/codeyu/nanoid-net/) 85 | 86 | ## License 87 | 88 | The MIT License (MIT). Please see [License File](LICENSE) for more information. -------------------------------------------------------------------------------- /nanoid_cpp/src/nanoid/crypto_random.cpp: -------------------------------------------------------------------------------- 1 | #include "nanoid/crypto_random.h" 2 | 3 | template void unused(T&&...) {} 4 | 5 | void NANOID_NAMESPACE::crypto_random_base::next_bytes(std::uint8_t* buffer, std::size_t size) 6 | { 7 | unused(buffer, size); 8 | } -------------------------------------------------------------------------------- /nanoid_cpp/src/nanoid/nanoid.cpp: -------------------------------------------------------------------------------- 1 | #include "nanoid/nanoid.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | static std::string _default_dict = "_0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; 9 | static std::size_t _default_size = 21; 10 | static NANOID_NAMESPACE::crypto_random _random(std::random_device{}()); 11 | 12 | using __gen_func_type = std::string(*)(NANOID_NAMESPACE::crypto_random_base&, const std::string&, std::size_t); 13 | 14 | int NANOID_NAMESPACE::impl::clz32(int x) 15 | { 16 | const int numIntBits = sizeof(int) * 8; //compile time constant 17 | //do the smearing 18 | x |= x >> 1; 19 | x |= x >> 2; 20 | x |= x >> 4; 21 | x |= x >> 8; 22 | x |= x >> 16; 23 | //count the ones 24 | x -= x >> 1 & 0x55555555; 25 | x = (x >> 2 & 0x33333333) + (x & 0x33333333); 26 | x = (x >> 4) + x & 0x0f0f0f0f; 27 | x += x >> 8; 28 | x += x >> 16; 29 | return numIntBits - (x & 0x0000003f); //subtract # of 1s from 32 30 | } 31 | 32 | std::string NANOID_NAMESPACE::generate() 33 | { 34 | return generate(_random, _default_dict, _default_size); 35 | } 36 | std::string NANOID_NAMESPACE::generate(const std::string& alphabet) 37 | { 38 | return generate(_random, alphabet, _default_size); 39 | } 40 | std::string NANOID_NAMESPACE::generate(std::size_t size) 41 | { 42 | return generate(_random, _default_dict, size); 43 | } 44 | std::string NANOID_NAMESPACE::generate(const std::string& alphabet, std::size_t size) 45 | { 46 | return generate(_random, alphabet, size); 47 | } 48 | 49 | std::future NANOID_NAMESPACE::generate_async() 50 | { 51 | return std::async 52 | ( 53 | (__gen_func_type)(generate), 54 | std::ref(static_cast(_random)), 55 | std::cref(_default_dict), _default_size 56 | ); 57 | } 58 | std::future NANOID_NAMESPACE::generate_async(const std::string& alphabet) 59 | { 60 | return std::async 61 | ( 62 | (__gen_func_type)(generate), 63 | std::ref(static_cast(_random)), 64 | alphabet, _default_size 65 | ); 66 | } 67 | std::future NANOID_NAMESPACE::generate_async(std::size_t size) 68 | { 69 | return std::async 70 | ( 71 | (__gen_func_type)(generate), 72 | std::ref(static_cast(_random)), 73 | std::cref(_default_dict), size 74 | ); 75 | } 76 | std::future NANOID_NAMESPACE::generate_async(const std::string& alphabet, std::size_t size) 77 | { 78 | return std::async 79 | ( 80 | (__gen_func_type)(generate), 81 | std::ref(static_cast(_random)), 82 | alphabet, size 83 | ); 84 | } 85 | 86 | std::string NANOID_NAMESPACE::generate(crypto_random_base& random) 87 | { 88 | return generate(random, _default_dict, _default_size); 89 | } 90 | std::string NANOID_NAMESPACE::generate(crypto_random_base& random, const std::string& alphabet) 91 | { 92 | return generate(random, alphabet, _default_size); 93 | } 94 | std::string NANOID_NAMESPACE::generate(crypto_random_base& random, std::size_t size) 95 | { 96 | return generate(random, _default_dict, size); 97 | } 98 | std::string NANOID_NAMESPACE::generate(crypto_random_base& random, const std::string& alphabet, std::size_t size) 99 | { 100 | if (alphabet.size() <= 0 || alphabet.size() >= 256) 101 | { 102 | throw std::invalid_argument("alphabet must contain between 1 and 255 symbols."); 103 | } 104 | 105 | if (size <= 0) 106 | { 107 | throw std::invalid_argument("size must be greater than zero."); 108 | } 109 | 110 | std::size_t alphSize = alphabet.size(); 111 | 112 | // See https://github.com/ai/nanoid/blob/master/format.js for 113 | // explanation why masking is use (`random % alphabet` is a common 114 | // mistake security-wise). 115 | const std::size_t mask = ( 2 << (31 - impl::clz32( (int)((alphSize - 1) | 1) )) ) - 1; 116 | const std::size_t step = (std::size_t)std::ceil(1.6 * mask * size / alphSize); 117 | 118 | auto idBuilder = std::string(size, '_'); 119 | auto bytes = std::vector(step); 120 | 121 | std::size_t cnt = 0; 122 | 123 | while (true) 124 | { 125 | 126 | random.next_bytes(bytes.data(), bytes.size()); 127 | 128 | for (std::size_t i = 0; i < step; i++) 129 | { 130 | 131 | std::size_t alphabetIndex = bytes[i] & mask; 132 | 133 | if (alphabetIndex >= alphSize) continue; 134 | idBuilder[cnt] = alphabet[alphabetIndex]; 135 | if (++cnt == size) 136 | { 137 | return std::string(idBuilder); 138 | } 139 | 140 | } 141 | 142 | } 143 | } -------------------------------------------------------------------------------- /nanoid_cpp/tests/unit_tests.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "nanoid/nanoid.h" 8 | 9 | #define CATCH_CONFIG_MAIN 10 | #include "catch2/catch.h" 11 | 12 | static std::string _default_dict = "_-0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; 13 | static std::size_t _default_size = 21; 14 | 15 | class predefined_random : public NANOID_NAMESPACE::crypto_random_base 16 | { 17 | public: 18 | using result_type = std::uint32_t; 19 | private: 20 | std::vector _sequence; 21 | public: 22 | predefined_random& operator=(const predefined_random& other) = delete; 23 | predefined_random(const predefined_random&) = delete; 24 | predefined_random(const std::vector& vec) : _sequence(vec) {} 25 | 26 | static constexpr result_type(min)() { 27 | return std::numeric_limits::min(); 28 | } 29 | 30 | static constexpr result_type(max)() { 31 | return std::numeric_limits::max(); 32 | } 33 | 34 | result_type operator()() { 35 | result_type res = _sequence[0]; 36 | } 37 | 38 | void next_bytes(std::uint8_t* buffer, std::size_t size) override 39 | { 40 | std::vector bytes; 41 | for (std::size_t i = 0; i < size; i += _sequence.size()) 42 | { 43 | bytes.insert( 44 | std::end(bytes), 45 | std::begin(_sequence), 46 | std::begin(_sequence) + std::min(size - i, _sequence.size()) 47 | ); 48 | } 49 | for (std::size_t i = 0; i < size; ++i) 50 | { 51 | //Have to revert order, because original uses reversed buffer, so double-reverse. 52 | buffer[i] = bytes[(size - i - 1)]; 53 | } 54 | } 55 | }; 56 | 57 | TEST_CASE("TestDefault") 58 | { 59 | std::string res = nanoid::generate(); 60 | REQUIRE(res.size() == _default_size); 61 | } 62 | 63 | TEST_CASE("TestCustomSize") 64 | { 65 | const std::size_t size = 10; 66 | std::string res = nanoid::generate(size); 67 | REQUIRE(res.size() == size); 68 | } 69 | 70 | TEST_CASE("TestCustomAlphabet") 71 | { 72 | const std::string alphabet = "1234abcd"; 73 | 74 | char buff[256]; 75 | snprintf(buff, sizeof(buff), "[%s]{%lu}$", alphabet.c_str(), _default_size); 76 | std::string regex = buff; 77 | 78 | std::string res = nanoid::generate(alphabet); 79 | REQUIRE(res.size() == _default_size); 80 | INFO(regex); 81 | REQUIRE_THAT(res, Catch::Matches(regex)); 82 | } 83 | 84 | TEST_CASE("TestCustomAlphabetAndSize") 85 | { 86 | const std::string alphabet = "1234abcd"; 87 | const std::size_t size = 7; 88 | std::string res = nanoid::generate(alphabet, size); 89 | 90 | char buff[256]; 91 | snprintf(buff, sizeof(buff), "[%s]{%lu}$", alphabet.c_str(), size); 92 | std::string regex = buff; 93 | 94 | REQUIRE(res.size() == size); 95 | INFO(regex); 96 | REQUIRE_THAT(res, Catch::Matches(regex)); 97 | } 98 | 99 | TEST_CASE("TestSingleLetterAlphabet") 100 | { 101 | const std::string alphabet = "a"; 102 | const std::size_t size = 5; 103 | std::string res = nanoid::generate(alphabet, size); 104 | REQUIRE(res == "aaaaa"); 105 | } 106 | 107 | TEST_CASE("TestPredefinedRandomSequence") 108 | { 109 | const std::vector seq{ 2, 255, 3, 7, 7, 7, 7, 7, 0, 1 }; 110 | predefined_random r(seq); 111 | 112 | using tp = std::pair; 113 | 114 | auto tests = GENERATE(tp(4, "adca"), tp(18, "cbadcbadcbadcbadcc")); 115 | 116 | const std::string alphabet = "abcde"; 117 | 118 | CHECK(nanoid::generate(r, alphabet, tests.first) == tests.second); 119 | } 120 | 121 | TEST_CASE("TestAsyncGenerate") 122 | { 123 | std::string res = nanoid::generate_async().get(); 124 | REQUIRE(res.size() == _default_size); 125 | } 126 | 127 | TEST_CASE("TestGeneratesUrlFriendlyIDs") 128 | { 129 | for (int i = 1; i <= 10; ++i) 130 | { 131 | std::string res = nanoid::generate(); 132 | REQUIRE(res.size() == _default_size); 133 | 134 | for (std::size_t j = 0; j < res.size(); ++j) 135 | { 136 | REQUIRE(res.find(res[j]) != std::string::npos); 137 | } 138 | } 139 | } 140 | //TODO - check this, it uses standard random_device 141 | TEST_CASE("TestHasNoCollisions") 142 | { 143 | const int count = 100 * 1000; 144 | std::map dictUsed; 145 | int fails = 0; 146 | for (std::size_t dummy = 1; dummy <= count; ++dummy) 147 | { 148 | std::string result = nanoid::generate(); 149 | auto it = dictUsed.find(result); 150 | fails += (it != dictUsed.end()); 151 | dictUsed[result] = true; 152 | } 153 | CHECK(fails == 0); 154 | } 155 | 156 | TEST_CASE("TestFlatDistribution") 157 | { 158 | const int count = 100 * 1000; 159 | std::map chars; 160 | for (std::size_t dummy = 1; dummy <= count; ++dummy) 161 | { 162 | auto id = nanoid::generate(); 163 | for (std::size_t i = 0; i < _default_size; i++) 164 | { 165 | auto c = id[i]; 166 | auto it = chars.find(c); 167 | if (it == chars.end()) 168 | { 169 | chars[c] = 0; 170 | } 171 | chars[c] += 1; 172 | } 173 | } 174 | 175 | for (auto c : chars) 176 | { 177 | auto distribution = c.second * _default_dict.size() / (double)(count * _default_size); 178 | REQUIRE(distribution == Approx(1.0).epsilon(0.05)); 179 | } 180 | } 181 | 182 | TEST_CASE("TestMask") 183 | { 184 | for (auto length = 1; length < 256; length++) 185 | { 186 | auto mask1 = (2 << (int)std::floor(std::log(length - 1) / std::log(2))) - 1; 187 | auto mask2 = (2 << 31 - NANOID_NAMESPACE::impl::clz32((length - 1) | 1)) - 1; 188 | REQUIRE(mask1 == mask2); 189 | } 190 | } --------------------------------------------------------------------------------