diff --git a/.clang-format b/.clang-format deleted file mode 100644 index c4a0e94..0000000 --- a/.clang-format +++ /dev/null @@ -1,61 +0,0 @@ ---- -Language: Cpp -# BasedOnStyle: Mozilla -AccessModifierOffset: -4 -ConstructorInitializerIndentWidth: 0 -AlignEscapedNewlinesLeft: false -AlignTrailingComments: true -AllowAllParametersOfDeclarationOnNextLine: true -AllowShortBlocksOnASingleLine: true -AllowShortCaseLabelsOnASingleLine: true -AllowShortIfStatementsOnASingleLine: true -AllowShortLoopsOnASingleLine: true -AllowShortFunctionsOnASingleLine: All -AlwaysBreakAfterDefinitionReturnType: true -AlwaysBreakTemplateDeclarations: true -AlwaysBreakBeforeMultilineStrings: true -BreakBeforeBinaryOperators: None -BreakBeforeTernaryOperators: true -BreakConstructorInitializersBeforeComma: true -BinPackParameters: false -BinPackArguments: false -ColumnLimit: 100 -ConstructorInitializerAllOnOneLineOrOnePerLine: true -DerivePointerAlignment: false -ExperimentalAutoDetectBinPacking: false -IndentCaseLabels: false -IndentWrappedFunctionNames: false -IndentFunctionDeclarationAfterType: false -MaxEmptyLinesToKeep: 1 -KeepEmptyLinesAtTheStartOfBlocks: false -NamespaceIndentation: None -ObjCSpaceAfterProperty: false -ObjCSpaceBeforeProtocolList: true -PenaltyBreakBeforeFirstCallParameter: 19 -PenaltyBreakComment: 300 -PenaltyBreakString: 1000 -PenaltyBreakFirstLessLess: 120 -PenaltyExcessCharacter: 1000000 -PenaltyReturnTypeOnItsOwnLine: 60 -PointerAlignment: Left -SpacesBeforeTrailingComments: 1 -Cpp11BracedListStyle: false -Standard: Cpp11 -IndentWidth: 4 -TabWidth: 8 -UseTab: Never -BreakBeforeBraces: Attach -SpacesInParentheses: false -SpacesInSquareBrackets: false -SpacesInAngles: false -SpaceInEmptyParentheses: false -SpacesInCStyleCastParentheses: false -SpaceAfterCStyleCast: false -SpacesInContainerLiterals: true -SpaceBeforeAssignmentOperators: true -ContinuationIndentWidth: 4 -CommentPragmas: '^ IWYU pragma:' -ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] -SpaceBeforeParens: ControlStatements -DisableFormat: false -... diff --git a/.gitignore b/.gitignore index 3f6901c..fa20c39 100644 --- a/.gitignore +++ b/.gitignore @@ -1,46 +1,15 @@ -# Compiled Object files -*.slo -*.lo -*.o -*.obj - -# Precompiled Headers -*.gch -*.pch - -# Compiled Dynamic libraries -*.so -*.dylib -*.dll - -# Fortran module files -*.mod - -# Compiled Static libraries -*.lai -*.la -*.a -*.lib - -# Executables -*.exe -*.out -*.app - # Results result.json -test-results.xml +*.xml -# Build -build/ - -# JetBrains +# IDE config .idea/ +.vscode/ # Deps -deps/boost/ -deps/jsoncpp/ -mysql-connector/ +cpp/deps/jsoncpp/ +cpp/deps/mysql-connector/ +cpp/deployment/cameradar_*_Release_Linux.tar.gz # Test test/cameradartest.conf.json diff --git a/.travis.yml b/.travis.yml index 90d43d8..2da32a1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,53 +6,13 @@ before_install: - echo "Testing Docker Hub credentials" - docker login -u=$DOCKER_USERNAME -p=$DOCKER_PASSWORD - echo "Docker Hub credentials are working" -- sudo apt-get update -qq -- sudo apt-get install -y software-properties-common -- sudo add-apt-repository -y ppa:mc3man/trusty-media -- sudo add-apt-repository -y ppa:george-edison55/cmake-3.x -- sudo apt-get update -qq -- sudo apt-get install -y nmap -- sudo apt-get install -y ffmpeg -- sudo apt-get install -y cmake -- sudo apt-get install -y libboost-all-dev -- sudo apt-get install -y libgstreamer1.0-dev -- sudo apt-get install -y gstreamer1.0-plugins-base -- sudo apt-get install -y gstreamer1.0-plugins-good -- sudo apt-get install -y libcurl4-openssl-dev -- sudo apt-get install -y libmysqlclient18 -- sudo apt-get install -y mysql-client install: -- export DEPS_DIR="${TRAVIS_BUILD_DIR}/deps" -- export PACKAGE_NAME="cameradar_*_Debug_Linux" - -matrix: - include: - - os: linux - env: TEST_TYPE='BUILD' WORKDIR='deployment' COMPILER_NAME=gcc CXX=g++-5 CC=gcc-5 CMAKE_CXX_COMPILER=g++-5 - addons: - apt: - packages: - - g++-5 - sources: &sources - - ubuntu-toolchain-r-test - - os: linux - env: TEST_TYPE='TEST' WORKDIR='test' COMPILER_NAME=gcc CXX=g++-5 CC=gcc-5 CMAKE_CXX_COMPILER=g++-5 - addons: - apt: - packages: - - g++-5 - sources: &sources - - ubuntu-toolchain-r-test +- docker build -t cameradar . script: -- cd ${WORKDIR} -- ./build_last_package.sh Debug -- tar xvf ${PACKAGE_NAME}.tar.gz -- find ${DEPS_DIR} -name "*.so*" -exec cp {} ${PACKAGE_NAME}/libraries \; -- tar -czvf ${PACKAGE_NAME}.tar.gz ${PACKAGE_NAME} -- if [[ "$TEST_TYPE" == "BUILD" ]]; then docker build -t cameradar . && docker run -v /tmp/thumbs:/tmp/thumbs cameradar; else ./test.sh ; fi +- docker run cameradar after_success: - echo "Test Success - Branch($TRAVIS_BRANCH) Pull Request($TRAVIS_PULL_REQUEST) Tag($TRAVIS_TAG)" -- if [[ "$TRAVIS_BRANCH" == "master" ]]; then echo -e "Push Container to Docker Hub" && docker login -u $DOCKER_USERNAME -p $DOCKER_PASSWORD && docker tag cameradar $DOCKER_REPO:$TRAVIS_TAG && docker tag cameradar $DOCKER_REPO:latest && docker push $DOCKER_REPO; fi +- if [[ "$TRAVIS_BRANCH" == "master" ]]; then echo -e "Push Container to Docker Hub" && docker login -u $DOCKER_USERNAME -p $DOCKER_PASSWORD && docker tag cameradar $DOCKER_REPO:latest && docker push $DOCKER_REPO; fi diff --git a/CHANGELOG.md b/CHANGELOG.md index ab87735..e396757 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,9 +2,19 @@ This file lists all versions of the repository and precises all changes. +## v2.0.0 + +#### Major changes: + +* Cameradar is no longer a C++ application but a Golang library +* Cameraccess is a Golang application replacing the former C++ one (the C++ Cameradar image can still be used with the tag `1.1.4`) +* The docker image for Cameraccess is lighter than the one for Cameradar +* The Cameradar golang library enables users to build their own application around camera discovery and attack. Example of applications could be an automatic camera discovery daemon with scheduled scans, a security audit tool to check if CCTV cameras are protected from attacks by being isolated and having strong passwords, etc. + ## v1.1.4 -#### Minor changes : +#### Minor changes: + * Simplified use of Docker image * Renamed MySQL table name to be more explicit * Refactoring of the Golang functional tester done @@ -14,18 +24,21 @@ This file lists all versions of the repository and precises all changes. * Updated dictionaries to add user suggestions for Chinese cameras * Enhanced `result.json` file's format -#### Bugfixes : +#### Bugfixes: + * Fixed a bug in the functional testing in which if the `result.json` file was not formatted correctly, the test failed but was still considered a success. ## v1.1.3 -#### Minor changes : +#### Minor changes: + * Added automatic pushes to DockerHub to the travis integration * Made travis configuration file better * Changed the package generation scripts to make them report errors * Removed old etix_rtsp_server binary from the test folder -#### Bugfixes : +#### Bugfixes: + * Fixed an issue that made it mandatory to launch tests at least once so that they can work the second time * Fixed an issue that made the golang testing tool not compile in the testing script * Fixed an issue that made the golang testing tool sometimes ignore some tests @@ -33,19 +46,22 @@ This file lists all versions of the repository and precises all changes. ## v1.1.2 -#### Minor changes : +#### Minor changes: + * Added travis integration * Added default environment value for Docker deployment * Updated docker image description with new easy usage * Updated README badges style (replaced flat with square-flat) * Build last package can now also generate a debug package if given the `Debug` command-line argument -#### Known issues : +#### Known issues + * There is still the issue with Camera Emulation Server, see the [previous version's patchnote](#v1.1.1) for more information. ## v1.1.1 -#### Minor changes : +#### Minor changes: + * Removed unnecessary null pointer checks (thanks to https://github.com/elfring) * Updated package description * Removed debug message in CMake build @@ -60,7 +76,8 @@ This file lists all versions of the repository and precises all changes. * JUnit output now contains errors which makes debugging much easier * Added header files where it was forgotten -#### Bugfixes : +#### Bugfixes: + * Fixed an issue where if you loose your internet connection during thumbnail generation, FFMpeg would get stuck forever and thus Cameradar would never finish * Fixed an issue where multithreading could cause crashes * Fixed an issue where the routes dictionary was mistaken for the credentials dictionary @@ -68,12 +85,14 @@ This file lists all versions of the repository and precises all changes. * Fixed automated camera generation * Fixed docker IP address resolution -#### Known issues : +#### Known issues: + * There is an issue with Camera Emulation Server that makes it impossible for Cameradar to generate thumbnails, which is why right now the verification of the thumbnails presence is commented and it is assumed correct. It is probably an issue with GST-RTSP-Server but requires investigation. ## v1.1.0 -#### Major changes : +#### Major changes: + * There are more command line options * Port can now be overridden in the command line * Target can now be overridden in the command line @@ -81,13 +100,15 @@ This file lists all versions of the repository and precises all changes. * Thumbnail generation is now multithreaded and will use as many threads as there are discovered cameras * There are now default configuration values in order to make cameradar easier to use -#### Minor changes : +#### Minor changes: + * The algorithms take external input into account (so that a 3rd party can change the DB to help Cameradar in real-time) and thus check the persistent data at each iteration * The default log level is now DEBUG instead of INFO * The attack logs are now INFO instead of DEBUG * The thumbnail generation logs are now INFO instead of DEBUG #### Bugs fixed + * Fixed a bug in which the MySQL cache manager would consider a camera with known ids as having a valid path even if it weren't * Fixed a bug in which TCP RTSP streams would not generate thumbnails @@ -98,23 +119,23 @@ This file lists all versions of the repository and precises all changes. ## v1.0.4 -#### Bugs fixed : +#### Bugs fixed: * Fixed nmap package detection ## v1.0.3 -#### Bugs fixed : +#### Bugs fixed: * Corrected GStreamer check ## v1.0.2 -#### Bugs fixed : +#### Bugs fixed: * Fixed issues in MySQL Cache Manager -#### Minor changes : +#### Minor changes: * Added useful debug logs @@ -122,11 +143,11 @@ This file lists all versions of the repository and precises all changes. ### Ubuntu 16.04 Release -#### Major changes : +#### Major changes: * The Docker deployment is now done using Ubuntu 16.04 instead of Ubuntu 15.10, so that it uses more recent packages. -#### Minor changes : +#### Minor changes: * Removed useless dependencies @@ -134,7 +155,7 @@ This file lists all versions of the repository and precises all changes. ### First production-ready release -#### Major changes : +#### Major changes: * Added functional testing @@ -142,15 +163,15 @@ This file lists all versions of the repository and precises all changes. After doing some testing on a weirdly configured camera network in a far away Datacenter, I discovered that some Cameras needed a few tweaks to the Cameradar attack method in order to be accessed. -#### Major changes : +#### Major changes: * Cameradar can access Cameras that are configured to always send 400 Bad Requests responses -#### Minor changes : +#### Minor changes: * Changed iterator name from `it` to `stream` in dumb cache manager to improve code readability -#### Bugfixes : +#### Bugfixes: * Cameradar no longer considers a timing out Camera as an accessible stream diff --git a/CMakeLists.txt b/CMakeLists.txt deleted file mode 100644 index 2948c4f..0000000 --- a/CMakeLists.txt +++ /dev/null @@ -1,130 +0,0 @@ -## Copyright 2016 Etix Labs -## -## Licensed under the Apache License, Version 2.0 (the "License"); -## you may not use this file except in compliance with the License. -## You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. - -cmake_minimum_required (VERSION 2.8.1) -cmake_policy(SET CMP0048 OLD) - -set (PROJECT_NAME cameradar) - -project (${PROJECT_NAME}) - -set (${PROJECT_NAME}_VERSION_MAJOR 1) -set (${PROJECT_NAME}_VERSION_MINOR 1) -set (${PROJECT_NAME}_VERSION_PATCH 4) -set (${PROJECT_NAME}_VERSION "${${PROJECT_NAME}_VERSION_MAJOR}.${${PROJECT_NAME}_VERSION_MINOR}.${${PROJECT_NAME}_VERSION_PATCH}${${PROJECT_NAME}_SUFFIX}") - -find_package(Git REQUIRED) - -# compiler flags -set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14") #enable C++14 -set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -W -Wall -Wextra -Wno-unused-function") # extra warnings -set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fdiagnostics-color") #enable error coloration on gcc - -# release specific flags -set (CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O2") - -#debug specific flags -set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g -fprofile-arcs -ftest-coverage") - -# rpath enable osx -set(CMAKE_MACOSX_RPATH 1) - -# list of all cache managers -set (CAMERADAR_CACHE_MANAGERS "") - -# dependencies directory -set(DEPS_DIR ${CMAKE_SOURCE_DIR}/deps) - -# output path for cache managers -set (CAMERADAR_CACHE_MANAGER_OUTPUT_FOLDER cache_managers) -set (CAMERADAR_CACHE_MANAGER_OUTPUT_PATH ${CMAKE_BINARY_DIR}/${CAMERADAR_CACHE_MANAGER_OUTPUT_FOLDER}) - -set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake) - -# the place where the version.h file is generated, used from the main.cpp of cameradar -set (VERSION_INCLUDE_DIR ${PROJECT_BINARY_DIR}) - -# get the git revision -message (STATUS "retrieve current git revision SHA1 of cameradar") -execute_process( - COMMAND "git" "rev-parse" "HEAD" - WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} - OUTPUT_VARIABLE CAMERADAR_GIT_SHA1 -) - -# remove last character of the git output (\n) -string(LENGTH ${CAMERADAR_GIT_SHA1} CAMERADAR_GIT_SHA1_LEN) -math(EXPR CAMERADAR_GIT_SHA1_LEN "${CAMERADAR_GIT_SHA1_LEN} - 1") -string(SUBSTRING ${CAMERADAR_GIT_SHA1} 0 ${CAMERADAR_GIT_SHA1_LEN} CAMERADAR_GIT_SHA1) - -# print the SHA1 -message (STATUS "current cameradar git revision SHA1 is ${CAMERADAR_GIT_SHA1}") - -# generate build number from the current timestamp -string(TIMESTAMP CAMERADAR_VERSION_BUILD "%Y%m%d%H%M%S" "UTC") - -# print version -message (STATUS "current cameradar build version will be ${CAMERADAR_VERSION_BUILD}") - -configure_file ( - "${PROJECT_SOURCE_DIR}/version.h.in" - "${PROJECT_BINARY_DIR}/version.h" -) - -# add all deps libraries to the link directories path -link_directories ( - # third party libraries - "deps/jsoncpp/src/deps.jsoncpp/src/lib_json" - "deps/boost/src/deps.boost/libs" - "deps/mysql-connector/lib" -) - -include_directories ( - "cameradar_standalone/include" - "deps/jsoncpp/src/deps.jsoncpp/include" - "deps/boost/src/deps.boost/include" - "deps/mysql-connector/include" -) - -set (${CAMERADAR_BINARIES} "") -set (${CAMERADAR_LIBRARIES} "") - -# Build cache managers -add_subdirectory (deps) -add_subdirectory (cameradar_standalone) -add_subdirectory (cache_managers) - -list (APPEND CAMERADAR_LIBRARIES ${CAMERADAR_INSTALL_DEPENDENCIES} ${CAMERADAR_LIBRARIES}) - -install (PROGRAMS ${CAMERADAR_BINARIES} DESTINATION bin) -install (FILES ${CAMERADAR_CACHE_MANAGERS} DESTINATION cache_managers) -install (FILES ${CAMERADAR_LIBRARIES} DESTINATION libraries) -install (DIRECTORY ${CMAKE_SOURCE_DIR}/deps/licenses DESTINATION libraries) - -# CPack configuration -include (InstallRequiredSystemLibraries) -set (CPACK_PACKAGE_DESCRIPTION_SUMMARY "cameradar") -set (CPACK_PACKAGE_VENDOR "Etix Labs") -set (CPACK_PACKAGE_DESCRIPTION_SUMMARY "Cameradar hacks its way into RTSP CCTV cameras") -set (CPACK_PACKAGE_FILE_NAME "${PROJECT_NAME}_${${PROJECT_NAME}_VERSION}_${CMAKE_BUILD_TYPE}_${CMAKE_SYSTEM_NAME}") -set (CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/README.md") -set (CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE") -set (CPACK_PACKAGE_VERSION_MAJOR "0") -set (CPACK_PACKAGE_VERSION_MINOR "2") -set (CPACK_PACKAGE_VERSION_PATCH "2") -set (CPACK_PACKAGE_INSTALL_DIRECTORY "${PROJECT_NAME}_${${PROJECT_NAME}_VERSION}") -set (CPACK_GENERATOR "TGZ") -set (CPACK_SOURCE_GENERATOR "TGZ") - -include(CPack) diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..735b793 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,23 @@ +FROM golang:alpine +WORKDIR /go/src/github.com/EtixLabs/cameradar/cameraccess + +COPY . /go/src/github.com/EtixLabs/cameradar + +RUN apk update && \ + apk upgrade && \ + apk add nmap nmap-nselibs nmap-scripts \ + curl-dev \ + gcc \ + libc-dev \ + git \ + pkgconfig + +RUN go get github.com/andelf/go-curl +RUN go get github.com/pkg/errors +RUN go get gopkg.in/go-playground/validator.v9 +RUN go get github.com/jessevdk/go-flags +RUN go get github.com/fatih/color + +RUN go install + +ENTRYPOINT /go/bin/cameraccess diff --git a/README.md b/README.md index 8328f3c..7f08311 100644 --- a/README.md +++ b/README.md @@ -1,259 +1,170 @@ # Cameradar -## An RTSP surveillance camera access multitool +## An RTSP stream access tool that comes with its library [![cameradar License](https://img.shields.io/badge/license-Apache-blue.svg?style=flat)](#license) [![Docker Pulls](https://img.shields.io/docker/pulls/ullaakut/cameradar.svg?style=flat)](https://hub.docker.com/r/ullaakut/cameradar/) [![Build](https://img.shields.io/travis/EtixLabs/cameradar/master.svg?style=flat)](https://travis-ci.org/EtixLabs/cameradar) +[![Go Report Card](https://goreportcard.com/badge/github.com/EtixLabs/cameradar)](https://goreportcard.com/report/github.com/EtixLabs/cameradar) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/6ab80cfa7069413e8e7d7e18320309e3)](https://www.codacy.com/app/brendan-le-glaunec/cameradar?utm_source=github.com&utm_medium=referral&utm_content=EtixLabs/cameradar&utm_campaign=Badge_Grade) [![Latest release](https://img.shields.io/github/release/EtixLabs/cameradar.svg?style=flat)](https://github.com/EtixLabs/cameradar/releases/latest) - #### Cameradar allows you to: -* **Detect open RTSP hosts** on any accessible target -* Get their public info (hostname, port, camera model, etc.) -* Launch automated dictionary attacks to get their **stream route** (for example /live.sdp) +* **Detect open RTSP hosts** on any accessible target host +* Detect which device model is streaming +* Launch automated dictionary attacks to get their **stream route** (e.g.: `/live.sdp`) * Launch automated dictionary attacks to get the **username and password** of the cameras -* **Generate thumbnails** from them to check if the streams are valid and to have a quick preview of their content -* Try to create a Gstreamer pipeline to check if they are **properly encoded** -* Print a summary of all the informations Cameradar could get - -#### And all of this in a _single command-line_. - -Of course, you can also call for individual tasks if you plug in a Database to Cameradar using the MySQL cache manager for example. You can create your own cache manager by following the simple example of the **dumb cache manager**. +* Retrieve a complete and user-friendly report of the results

## Table of content - [Docker Image](#docker-image) -- [Quick install](#quick-install) - - [Dependencies](#quick-install###dependencies) - - [Five steps guide](#quick-install###five-steps-guide) -- [Manual installation](#manual-installation) - - [Dependencies](#manual-installation###dependencies) - - [Steps](#manual-installation###Steps) -- [Advanced docker deployment](#advanced-docker-deployment) - - [Dependencies](#advanced-docker-deployment###dependencies) - - [Deploy a custom version of Cameradar](#advanced-docker-deployment###deploy-a-custom-version-of-cameradar) - [Configuration](#configuration) - [Output](#output) - [Check camera access](#check-camera-access) - [Command line options](#command-line-options) -- [Next improvements](#next-improvements) - [Contribution](#contribution) - [Frequently Asked Questions](#frequently-asked-questions) - [License](#license) -## Docker Image +## Docker Image for Cameraccess -This is the fastest and simplest way to use Cameradar. To do this you will just need `docker` on your machine. +Install [docker](https://docs.docker.com/engine/installation/) on your machine, and run the following command: -Run - -``` -docker run -v /tmp/thumbs/:/tmp/thumbs \ - -e CAMERAS_TARGET=your_target \ - ullaakut/cameradar:tag +```bash +docker run ullaakut/cameradar ``` -* `your_target` can be a subnet (e.g.: `172.16.100.0/24`) or even an IP (e.g.: `172.16.100.10`), a range of IPs (e.g.: `172.16.100.10-172.16.100.20`) or a mix of all those separated by commas (e.g.: `172.17.100.0/24,172.16.100.10-172.16.100.20,0.0.0.0`). -* `tag` allows you to specify a specific version for camerada. If you don't specify any tag, you will use the latest version by default (recommended) +[See command-line options](#command-line-options). + +e.g.: `docker run ullaakut/cameradar -t 192.168.100.0/24 -l` will scan the ports 554 and 8554 of hosts on the 192.168.100.0/24 subnetwork and attack the discovered RTSP streams and will output lots of logs. + +* `YOUR_TARGET` can be a subnet (e.g.: `172.16.100.0/24`) or even an IP (e.g.: `172.16.100.10`), a range of IPs (e.g.: `172.16.100.10-172.16.100.20`) or a mix of all those separated by commas (e.g.: `172.17.100.0/24,172.16.100.10-172.16.100.20,0.0.0.0`). +* If you want to get the precise results of the nmap scan in the form of an XML file, you can add `-v /your/path:/tmp/cameradar_scan.xml` to the docker run command, before `ullaakut/cameradar`. +* If you use the `-r` and `-c` options to specify your Check [Cameradar's readme on the Docker Hub](https://hub.docker.com/r/ullaakut/cameradar/) for more information and more command-line options. -The generated thumbnails will be in `/tmp/thumbs` on both your machine and the `cameradar` container. - For more complex use of the Docker image, see the `Environment variables` part of [Cameradar's readme on the Docker Hub](https://hub.docker.com/r/ullaakut/cameradar/). -## Quick install +### Library -The quick install uses docker to build Cameradar without polluting your machine with dependencies and makes it easy to deploy Cameradar in a few commands. **However, it may require networking knowledge, as your docker containers will need access to the cameras subnetwork.** +### Dependencies of the library -### Dependencies +- `curl-dev` / `libcurl` (depending on your OS) +- `nmap` +- `github.com/pkg/errors` +- `gopkg.in/go-playground/validator.v9` +- `github.com/andelf/go-curl` -The only dependencies are `docker`, `docker-tools`, `git` and `make`. +#### Installing the library -### Five steps guide +```bash + go get github.com/EtixLabs/cameradar +``` -1. `git clone https://github.com/EtixLabs/cameradar.git` -2. `cd cameradar/deployment` -3. Tweak the `conf/cameradar.conf.json` as you need (see [the configuration guide here](#configuration) for more information) -4. `docker-compose build ; docker-compose up` +After this command, the *cameradar* library is ready to use. Its source will be in: -By default, the version of the package in the deployment should be the last stable release. + $GOPATH/src/pkg/github.com/EtixLabs/cameradar -If you want to scan a different target or different ports, change the values `CAMERAS_TARGET` and `CAMERAS_PORTS` in the `docker-compose.yml` file. +You can use `go get -u` to update the package. -The generated thumbnails will be in the `cameradar_thumbnails` folder after Cameradar has finished executing. +Here is an overview of the exposed functions of this library: -If you want to deploy your custom version of Cameradar using the same method, you should check the [advanced docker deployment](#advanced-docker-deployment) tutorial here. +#### Discovery -## Manual installation +You can use the cameradar library for simple discovery purposes if you don't need to access the cameras but just to be aware of their existence. -The manual installation is recommended if you want to tweak Cameradar and quickly test them using CMake and running Cameradar in command-line. If you just want to use Cameradar, it is recommended to use the [quick install](#quick-install) instead. +

+The Discover function calls the RunNmap function as well as the ParseNmapResults function and returns the discovered streams without attempting any attack. +It will use default values for its calls to RunNmap: -### Dependencies +

+This describes the nmap time presets. You can pass a value between 1 and 5 as described in this table, to the RunNmap function. -To install Cameradar you will need these packages +

+The RunNmap function will execute nmap and generate an XML file containing the results of the scan. -* cmake (`cmake`) -* git (`git`) -* gstreamer1.x (`libgstreamer1.0-dev`) -* ffmpeg (`ffmpeg`) -* boost (`libboost-all-dev`) -* libcurl (`libcurl4-openssl-dev`) +

+The ParseNmapResult function will open the specified XML file and return all open RTSP streams found within it. -### Steps +#### Attack -The simplest way would be to follow these steps : +If you already know which hosts and ports you want to attack, you can also skip the discovery part and use directly the attack functions. The attack functions also take a timeout value as a parameter. -1. `git clone https://github.com/EtixLabs/cameradar.git` -2. `cd cameradar` -3. `mkdir build` -4. `cd build` -5. `cmake ..` -6. `make` -7. `cd cameradar_standalone` -8. `./cameradar -s the_target_you_want_to_scan` +

+The AttackCredentials function takes valid streams as an input (with IP addresses and ports) and will attempt to guess their credentials using the provided dictionary. -## Advanced Docker deployment +

+The AttackRoute function takes valid streams as an input (with IP addresses and ports) and will attempt to guess their routes using the provided dictionary. -In case you want to use Docker to deploy your custom version of Cameradar. +#### Data models -### Dependencies +Here are the different data models useful to use the exposed functions of the cameradar library. -The only dependencies are `docker` and `docker-compose`. +

-### Using the package generation script -1. `git clone https://github.com/EtixLabs/cameradar.git` -2. `cd cameradar/deployment` -3. `rm *.tar.gz` -4. `./build_last_package.sh` -5. `docker-compose build cameradar` -6. `docker-compose up cameradar` +#### Dictionary loaders -### Deploy a custom version of Cameradar by hand +The cameradar library also provides two functions that take file paths as inputs and return the appropriate data models filled. -1. `git clone https://github.com/EtixLabs/cameradar.git` -2. `cd cameradar` -3. `mkdir build` -4. `cd build` -5. `cmake .. -DCMAKE_BUILD_TYPE=Release` -6. `make package` -7. `cp cameradar_*_Release_Linux.tar.gz ../deployment` -8. `cd ../deployment` -9. `docker-compose build cameradar` -10. `docker-compose up cameradar` +

+ +LoadCredentials takes a JSON file that has the same format as [this one](dictionary/credentials.json). + +

+ +LoadRoutes takes a file that has the same format as [this one](dictionary/routes). Warning: This file is not JSON. ### Configuration -Here is the basic content of the configuration file with simple placeholders : -```json -{ - "mysql_db" : { - "host" : "MYSQL_SERVER_IP_ADDRESS", - "port" : MYSQL_SERVER_PORT, - "user": "root", - "password": "root", - "db_name": "cmrdr" - }, - "target" : "target1,target2,target3,[...]", - "ports" : "PORT1,PORT2,[...]", - "rtsp_url_file" : "/path/to/url/dictionary", - "rtsp_ids_file" : "/path/to/url/dictionary", - "thumbnail_storage_path" : "/valid/path/to/a/storage/directory", - "cache_manager_path" : "/path/to/cache/manager", - "cache_manager_name" : "CACHE_MANAGER_NAME" -} +The **RTSP port used for most cameras is 554**, so you should probably specify 554 as one of the ports you scan. Not specifying any ports to the cameraccess application will scan the 554 and 8554 ports. + +e.g.: `docker run ullaakut/cameradar -p "18554,19000-19010" -t localhost` will scan the ports 18554, and the range of ports between 19000 and 19010 on localhost. + +You **can use your own files for the ids and routes dictionaries** used to attack the cameras, but the Cameradar repository already gives you a good base that works with most cameras, in the `/dictionaries` folder. + +e.g.: ```bash +docker run -v /my/folder/with/dictionaries:/tmp/dictionaries \ + ullaakut/cameradar \ + -r "/tmp/dictionaries/my_routes" \ + -c "/tmp/dictionaries/my_credentials.json" \ + -t 172.19.124.0/24 ``` -This **configuration is needed only if you want to overwrite the default values**, which are : - -```json -{ - "target" : "localhost", - "ports" : "554,8554", - "rtsp_url_file" : "conf/url.json", - "rtsp_ids_file" : "conf/ids.json", - "thumbnail_storage_path" : "/tmp", - "cache_manager_path" : "../cache_managers/dumb_cache_manager", - "cache_manager_name" : "dumb" -} -``` - -This means that **by default Cameradar will not use a database**, will scan localhost and the ports 554 (default RTSP port) and 8554 (default emulated RTSP port), use the default constructor dictionaries and store the thumbnails in `/tmp`. If you need to override simply the target or ports, you can use the [command line options](#command-line-options). - -The targets should be passed separated by commas only, and their target format should be the same as used in nmap. -```json -"target" : "172.100.16.0/24,172.100.17.0/24,localhost,192.168.1.13" -``` - -The **RTSP ports for most cameras are 554**, so you should probably specify 554 as one of the ports you scan. Not giving any ports in the configuration will scan every port of every host found on the target. - -You **can use your own files for the ids and routes dictionaries** used to attack the cameras, but the Cameradar repository already gives you a good base that works with most cameras. - -The thumbnail storage path should be a **valid and accessible directory** in which the thumbnails will be stored. - -The cache manager path and name variables are used to change the cache manager you want to load into Cameradar. If you want to, you can code your own cache manager using a database, a file, a remote server, [...]. Feel free to share it by creating a merge request on this repository if you developed a generic manager (It must not be specific to your company's infrastructure). +This will put the contents of your folder containing dictionaries in the docker image and will use it for the dictionary attack instead of the default dictionaries provided in the cameradar repo. ## Output -For each camera, Cameradar will output these JSON objects : +For each camera, Cameraccess will output this: + +

-```json -{ - "address" : "173.16.100.45", - "ids_found" : true, - "password" : "123456", - "path_found" : true, - "port" : 554, - "product" : "Vivotek FD9381-HTV", - "protocol" : "tcp", - "route" : "/live.sdp", - "service_name" : "rtsp", - "state" : "open", - "thumbnail_path" : "/tmp/127.0.0.1/1463735257.jpg", - "username" : "admin" -} -``` ## Check camera access -If you have [VLC Media Player](http://www.videolan.org/vlc/), you should be able to use the GUI to connect to the RTSP stream using this format : `rtsp://username:password@address:port/route` +If you have [VLC Media Player](http://www.videolan.org/vlc/), you should be able to use the GUI or the command-line to connect to the RTSP stream using this format : `rtsp://username:password@address:port/route` -With the above result, the RTSP URL would be `rtsp://admin:123456@173.16.100.45:554/live.sdp` - -If you're still in your console however, you can go even faster by using **vlc in commmand-line** and just run `vlc rtsp://username:password@address:port/route` with the camera's info instead of the placeholders. +With the above result, the RTSP URL would be `rtsp://admin:12345@173.16.100.45:554/live.sdp` ## Command line options -* **"-c"** : Set a custom path to the configuration file (-c /path/to/conf) -* **"-s"** : Set custom target (overrides configuration) : You can use this argument in many ways, using a subnet (e.g.: `172.16.100.0/24`) or even an IP (e.g.: `172.16.100.10`), a range of IPs (e.g.: `172.16.100.10-172.16.100.20`) or a mix of all those (e.g.: `172.17.100.0/24,172.16.100.10-172.16.100.20,0.0.0.0`) -* **"-p"** : Set custom ports (overrides configuration) -* **"-m"** : Set number of threads (*Default value : 1*) -* **"-l"** : Set log level - * **"-l 1"** : Log level DEBUG - * _Will print everything including debugging logs_ - * **"-l 2"** : Log level INFO - * _Prints every normal information_ - * **"-l 4"** : Log level WARNING - * _Only prints warning and errors_ - * **"-l 5"** : Log level ERROR - * _Only prints errors_ - * **"-l 6"** : Log level CRITICAL - * _Doesn't print anything since Cameradar can't have critical failures right now, however you can use this level to debug your own code easily or if you add new critical layers_ -* **"-d"** : Launch the discovery tool -* **"-b"** : Launch the dictionary attack tool on all discovered devices - * Needs either to be launched with the -d option or to use an advanced cache manager (DB, file, ...) with data already present -* **"-t"** : Generate thumbnails from detected cameras - * Needs either to be launched with the -d option or to use an advanced cache manager (DB, file, ...) with data already present -* **"-g"** : Check if the stream can be opened with GStreamer - * Needs either to be launched with the -d option or to use an advanced cache manager (DB, file, ...) with data already present -* **"-v"** : Display Cameradar's version -* **"-h"** : Display this help -* **"--gst-rtsp-server"** : Use this option if the attack does not seem to work (only detects the username but not the path, or the opposite). This option will switch the order of the attacks to prioritize path over credentials, which is the way priority is handled for cameras that use GStreamer's RTSP server. +* **"-t, --target"**: Set custom target. Required. +* **"-p, --ports"**: (Default: `554,8554`) Set custom ports. +* **"-s, --speed"**: (Default: `4`) Set custom nmap discovery presets to improve speed or accuracy. It's recommended to lower it if you are attempting to scan an unstable and slow network, or to increase it if on a very performant and reliable network. See [this for more info on the nmap timing templates](https://nmap.org/book/man-performance.html). +* **"-T, --timeout"**: (Default: `1000`) Set custom timeout value in miliseconds after which an attack attempt without an answer should give up. +* **"-r, --custom-routes"**: (Default: `dictionaries/routes`) Set custom dictionary path for routes +* **"-c, --custom-credentials"**: (Default: `dictionaries/credentials.json`) Set custom dictionary path for credentials +* **"-o, --nmap-output"**: (Default: `/tmp/cameradar_scan.xml`) Set custom nmap output path +* **"-l, --log"**: Enable debug logs (nmap requests, curl describe requests, etc.) +* **"-h"** : Display the usage information + +## Environment variables + +TODO ## Contribution @@ -261,25 +172,29 @@ See [the contribution document](/CONTRIBUTION.md) to get started. ## Frequently Asked Questions -> My camera's credentials are guessed by Cameradar but the RTSP URL is not! - -Your camera probably uses GST RTSP Server internally. Try the `--gst-rtsp-server` command-line option, and if it does not work, send me the Cameradar output in DEBUG mode (`-l 1`) and I will help you. - > Cameradar does not detect any camera! -That means that either your cameras are not streaming in RTSP or that they are not on the target you are scanning. In most cases, CCTV cameras will be on a private subnetwork. Use the `-s` option to specify your target. +That means that either your cameras are not streaming in RTSP or that they are not on the target you are scanning. In most cases, CCTV cameras will be on a private subnetwork, isolated from the internet. Use the `-t` option to specify your target. > Cameradar detects my cameras, but does not manage to access them at all! -Maybe your cameras have been configured and the credentials / URL have been changed. Cameradar only guesses using default constructor values. However, you can use your own dictionary in which you just have to add your passwords. To do that, see how the [configuration](#configuration) works. Also, maybe your camera's credentials are not yet known, in which case if you find them it would be very nice to add them to the Cameradar dictionaries to help other people in the future. +Maybe your cameras have been configured and the credentials / URL have been changed. Cameradar only guesses using default constructor values if a custom dictionary is not provided. You can use your own dictionaries in which you just have to add your credentials and RTSP routes. To do that, see how the [configuration](#configuration) works. Also, maybe your camera's credentials are not yet known, in which case if you find them it would be very nice to add them to the Cameradar dictionaries to help other people in the future. -> It does not compile :( +> What happened to the C++ version? -You probably missed the part with the dependencies! Use the quick docker deployment, it will be easier and will not pollute your machine with useless dependencies! `;)` +You can still find it under the 1.1.4 tag on this repo, however it was less performant and stable than the current version written in Golang. + +> How to use the Cameradar library for my own project? + +See the cameraccess example. You just need to run `go get github.com/EtixLabs/cameradar/cameradar` and to use the `cmrdr` package in your code. + +> I want to scan my own localhost for some reason and it does not work! What's going on? + +Use the `--net=host` flag when launching the cameradar image, or use the binary by running `go run cameraccess/main.go`. ## License -Copyright 2016 Etix Labs +Copyright 2017 Etix Labs Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/cache_managers/CMakeLists.txt b/cache_managers/CMakeLists.txt deleted file mode 100644 index 03b9ccd..0000000 --- a/cache_managers/CMakeLists.txt +++ /dev/null @@ -1,24 +0,0 @@ -## Copyright 2016 Etix Labs -## -## Licensed under the Apache License, Version 2.0 (the "License"); -## you may not use this file except in compliance with the License. -## You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. - -cmake_minimum_required (VERSION 2.8.1) -cmake_policy(SET CMP0042 NEW) - -# set temporarly the ouput path for all server plugins -set (LIBRARY_OUTPUT_PATH ${CAMERADAR_CACHE_MANAGER_OUTPUT_PATH}) - -add_subdirectory(dumb_cache_manager) -add_subdirectory(mysql_cache_manager) - -set (CAMERADAR_CACHE_MANAGERS ${CAMERADAR_CACHE_MANAGERS} PARENT_SCOPE) diff --git a/cache_managers/dumb_cache_manager/CMakeLists.txt b/cache_managers/dumb_cache_manager/CMakeLists.txt deleted file mode 100644 index 9ea4b47..0000000 --- a/cache_managers/dumb_cache_manager/CMakeLists.txt +++ /dev/null @@ -1,33 +0,0 @@ -## Copyright 2016 Etix Labs -## -## Licensed under the Apache License, Version 2.0 (the "License"); -## you may not use this file except in compliance with the License. -## You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. - -cmake_minimum_required (VERSION 2.8.1) -cmake_policy(SET CMP0042 NEW) - -project(dumb_cache_manager CXX) - -find_package(PkgConfig) - -include_directories (${PROJECT_SOURCE_DIR}/include ${CAMERADAR_INCLUDES}) - -include (find_sources) -find_sources ("src" "include") - -add_library (dumb_cache_manager SHARED ${SOURCES}) -set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--no-undefined") -target_link_libraries (dumb_cache_manager) - -set (CACHE_MANAGER_NAME ${CAMERADAR_CACHE_MANAGER_OUTPUT_PATH}/${CMAKE_SHARED_LIBRARY_PREFIX}dumb_cache_manager${CMAKE_SHARED_LIBRARY_SUFFIX}) -list (APPEND CAMERADAR_CACHE_MANAGERS ${CACHE_MANAGER_NAME}) -set (CAMERADAR_CACHE_MANAGERS ${CAMERADAR_CACHE_MANAGERS} PARENT_SCOPE) diff --git a/cache_managers/dumb_cache_manager/include/dumb_cache_manager.h b/cache_managers/dumb_cache_manager/include/dumb_cache_manager.h deleted file mode 100644 index 32a9461..0000000 --- a/cache_managers/dumb_cache_manager/include/dumb_cache_manager.h +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2016 Etix Labs -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -#include -#include -#include -#include -#include - -namespace etix { -namespace cameradar { - -class dumb_cache_manager : public cache_manager_base { -private: - static const std::string name; - std::vector streams; - std::shared_ptr configuration; - - std::mutex m; - -public: - using cache_manager_base::cache_manager_base; - ~dumb_cache_manager(); - - const std::string& get_name() const override; - static const std::string& static_get_name(); - bool load_dumb_conf(std::shared_ptr configuration); - bool configure(std::shared_ptr configuration) override; - - bool has_changed(const etix::cameradar::stream_model&); - - void set_streams(std::vector model); - - void update_stream(const etix::cameradar::stream_model& newmodel); - - std::vector get_streams(); - - std::vector get_valid_streams(); -}; -} -} diff --git a/cache_managers/dumb_cache_manager/src/dumb_cache_manager.cpp b/cache_managers/dumb_cache_manager/src/dumb_cache_manager.cpp deleted file mode 100644 index 041f06b..0000000 --- a/cache_managers/dumb_cache_manager/src/dumb_cache_manager.cpp +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright 2016 Etix Labs -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include - -namespace etix { -namespace cameradar { - -const std::string dumb_cache_manager::name = "dumb-cache-manager"; - -dumb_cache_manager::~dumb_cache_manager() {} - -const std::string& -dumb_cache_manager::get_name() const { - return dumb_cache_manager::static_get_name(); -} - -const std::string& -dumb_cache_manager::static_get_name() { - return dumb_cache_manager::name; -} - -bool -dumb_cache_manager::configure(std::shared_ptr configuration) { - return this->load_dumb_conf(configuration); -} - -bool -dumb_cache_manager::load_dumb_conf(std::shared_ptr configuration) { - this->configuration = configuration; - - return true; -} - -//! Replaces all cached streams by the content of the vector given as -//! parameter -void -dumb_cache_manager::set_streams(std::vector model) { - std::lock_guard lock(m); - this->streams = model; -} - -//! Inserts a single stream to the cache -void -dumb_cache_manager::update_stream(const etix::cameradar::stream_model& newmodel) { - std::lock_guard lock(m); - for (auto& stream : this->streams) { - if (stream.address == newmodel.address && stream.port == newmodel.port) { - stream = newmodel; - } - } -} - -//! Gets all cached streams -std::vector -dumb_cache_manager::get_streams() { - std::vector ret; - for (const auto& stream : this->streams) { - if (not stream.service_name.compare("rtsp") && not stream.state.compare("open")) - ret.push_back(stream); - } - return ret; -} - -//! Gets all valid streams -std::vector -dumb_cache_manager::get_valid_streams() { - std::vector ret; - for (const auto& stream : this->streams) { - if (stream.ids_found && stream.path_found) ret.push_back(stream); - } - return ret; -} - -// Returns true if the stream passed as a parameter has changed in the cache -bool -dumb_cache_manager::has_changed(const etix::cameradar::stream_model& old) { - for (const auto& stream : this->streams) { - if (stream.address == old.address) - if (stream.path_found != old.path_found || stream.ids_found != old.ids_found) - return true; - } - return false; -} - -extern "C" { -cache_manager_iface* -cache_manager_instance_new() { - return new dumb_cache_manager(); -} -} -} -} diff --git a/cache_managers/mysql_cache_manager/CMakeLists.txt b/cache_managers/mysql_cache_manager/CMakeLists.txt deleted file mode 100644 index f181a53..0000000 --- a/cache_managers/mysql_cache_manager/CMakeLists.txt +++ /dev/null @@ -1,33 +0,0 @@ -## Copyright 2016 Etix Labs -## -## Licensed under the Apache License, Version 2.0 (the "License"); -## you may not use this file except in compliance with the License. -## You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. - -cmake_minimum_required (VERSION 2.8.1) -cmake_policy(SET CMP0042 NEW) - -project(mysql_cache_manager CXX) - -find_package(PkgConfig) - -include_directories (${PROJECT_SOURCE_DIR}/include ${CAMERADAR_INCLUDES}) - -include (find_sources) -find_sources ("src" "include") - -add_library (mysql_cache_manager SHARED ${SOURCES}) -set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--no-undefined") -target_link_libraries (mysql_cache_manager jsoncpp mysqlcppconn pthread) - -set (CACHE_MANAGER_NAME ${CAMERADAR_CACHE_MANAGER_OUTPUT_PATH}/${CMAKE_SHARED_LIBRARY_PREFIX}mysql_cache_manager${CMAKE_SHARED_LIBRARY_SUFFIX}) -list (APPEND CAMERADAR_CACHE_MANAGERS ${CACHE_MANAGER_NAME}) -set (CAMERADAR_CACHE_MANAGERS ${CAMERADAR_CACHE_MANAGERS} PARENT_SCOPE) diff --git a/cache_managers/mysql_cache_manager/include/db_conn.h b/cache_managers/mysql_cache_manager/include/db_conn.h deleted file mode 100644 index 45acc40..0000000 --- a/cache_managers/mysql_cache_manager/include/db_conn.h +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright 2016 Etix Labs -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -#include // for ResultSet -#include // for mutex -#include // for bool, false -#include // for string -#include // for pair, make_pair - -#include "query_result.h" - -namespace sql { -class Connection; -class Driver; -class ResultSet; -} - -namespace etix { - -namespace cameradar { - -namespace mysql { - -//! MySQL Database connection handling -//! Abstracts all connection to the database -class db_connection { -private: - static const std::string create_database_query; - - //! SQL driver - sql::Driver* driver = nullptr; - //! SQL connection - sql::Connection* connection = nullptr; - std::mutex access_mtx; - bool connected = false; - - std::string db_name; - - //! Create the database if it doesn't exist at connector launch - empty_result create_database(void); - -public: - db_connection(void); - ~db_connection(void); - - //! Try to connect to the database - std::pair connect(const std::string& host, - const std::string& user, - const std::string& pass, - const std::string& db_name, - bool create_db_if_not_exist = true); - - //! Execute a MySQL command - empty_result execute(const std::string& request); - - //! Execute a query - query_result query(const std::string& query); - - bool is_connected(); - - //! Return db_name - const std::string& - get_db_name(void) const { - return this->db_name; - } -}; - -} // mysql - -} // cameradar - -} // etix diff --git a/cache_managers/mysql_cache_manager/include/mysql_cache_manager.h b/cache_managers/mysql_cache_manager/include/mysql_cache_manager.h deleted file mode 100644 index 2d79dd5..0000000 --- a/cache_managers/mysql_cache_manager/include/mysql_cache_manager.h +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright 2016 Etix Labs -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -#include -#include -#include -#include -#include -#include -#include - -namespace etix { - -namespace cameradar { - -struct mysql_configuration { - unsigned int port; - std::string host; - std::string db_name; - std::string user; - std::string password; - - mysql_configuration() = default; - - mysql_configuration(unsigned int port, - const std::string& host, - const std::string& db_name, - const std::string& user = "", - const std::string& password = "") - : port(port), host(host), db_name(db_name), user(user), password(password) {} -}; - -class mysql_cache_manager : public cache_manager_base { -private: - static const std::string name; - std::vector streams; - std::shared_ptr configuration; - etix::cameradar::mysql_configuration db_conf; - etix::cameradar::mysql::db_connection connection; - - std::mutex m; - - static const std::string create_table_query; - static const std::string insert_with_id_query; - static const std::string exist_query; - static const std::string get_results_query; - static const std::string update_result_query; - -public: - using cache_manager_base::cache_manager_base; - ~mysql_cache_manager(); - - // Specific to MySQL - bool execute_query(const std::string& query); - - const std::string& get_name() const override; - static const std::string& static_get_name(); - bool load_mysql_conf(std::shared_ptr configuration); - bool configure(std::shared_ptr configuration) override; - - bool has_changed(const etix::cameradar::stream_model&); - - void set_streams(std::vector model); - - void update_stream(const etix::cameradar::stream_model& newmodel); - - std::vector get_streams(); - - std::vector get_valid_streams(); -}; -} -} diff --git a/cache_managers/mysql_cache_manager/include/query_result.h b/cache_managers/mysql_cache_manager/include/query_result.h deleted file mode 100644 index 184f3da..0000000 --- a/cache_managers/mysql_cache_manager/include/query_result.h +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2016 Etix Labs -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -namespace etix { - -namespace cameradar { - -namespace mysql { - -enum class execute_result { success, not_found, no_row_updated, sql_error, error }; - -//! Wrapper of a DB query result -//! Templated on the data type we want to return (list, bool, whatever) -template -struct query_result { - DataType data; - execute_result state; - std::string error_msg; - - inline bool - success(void) const { - return state == execute_result::success; - } - inline bool - error(void) const { - return not success(); - } -}; - -//! Empty query result for when we just want to return the status -//! of the request with no associated data -template <> -struct query_result { - execute_result state; - std::string error_msg; - - inline bool - success(void) const { - return state == execute_result::success; - } - inline bool - error(void) const { - return not success(); - } -}; -typedef query_result empty_result; - -} //! mysql - -} //! cameradar - -} //! etix diff --git a/cache_managers/mysql_cache_manager/src/db_conn.cpp b/cache_managers/mysql_cache_manager/src/db_conn.cpp deleted file mode 100644 index c17f0d8..0000000 --- a/cache_managers/mysql_cache_manager/src/db_conn.cpp +++ /dev/null @@ -1,138 +0,0 @@ -// Copyright 2016 Etix Labs -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "db_conn.h" // for db_connection -#include "cppconn/connection.h" // for Connection -#include "query_result.h" // for queries -#include // for get_driver_instance, etc -#include // for SQLException -#include // for Statement -#include // for fmt -#include // for LOG_ - -namespace etix { - -namespace cameradar { - -namespace mysql { - -const std::string db_connection::create_database_query = "CREATE DATABASE IF NOT EXISTS %s"; - -db_connection::db_connection() : connected(false) {} - -db_connection::~db_connection() { delete this->connection; } - -std::pair -db_connection::connect(const std::string& host, - const std::string& user, - const std::string& pass, - const std::string& db_name, - bool create_db_if_not_exist) { - this->db_name = db_name; - - try { - this->driver = get_driver_instance(); - if (this->driver == nullptr) { - return std::make_pair(false, "Cannot instantiate sql_driver"); - } - this->connection = driver->connect(host, user, pass); - if (this->connection == nullptr) return std::make_pair(false, "Cannot connect to mysql"); - - this->connected = true; - if (create_db_if_not_exist) { - auto cdb = this->create_database(); - if (cdb.state == mysql::execute_result::sql_error) { return { false, cdb.error_msg }; } - this->connection->setSchema(db_name); - } - } catch (sql::SQLException& e) { - this->connected = false; - return { false, e.what() }; - } - - return std::make_pair(true, ""); -} - -empty_result -db_connection::execute(const std::string& request) { - std::lock_guard lock(this->access_mtx); - - sql::Statement* stmt = nullptr; - empty_result return_value = { execute_result::success, "" }; - - if (!this->is_connected()) { - return { execute_result::sql_error, "Error, not connected to MySQL database" }; - } - - try { - stmt = this->connection->createStatement(); - stmt->execute(request); - if (stmt->getUpdateCount() == 0) { - return_value = { execute_result::no_row_updated, "No row updated" }; - } - } catch (sql::SQLException& e) { return_value = { execute_result::sql_error, e.what() }; } - delete stmt; - - return return_value; -} - -query_result -db_connection::query(const std::string& query) { - std::lock_guard lock(this->access_mtx); - - sql::Statement* stmt = nullptr; - query_result return_value = { nullptr, execute_result::success, "" }; - - if (!this->is_connected()) { - return { nullptr, execute_result::sql_error, "Error, not connected to MySQL database" }; - } - - try { - stmt = this->connection->createStatement(); - return_value = { stmt->executeQuery(query), execute_result::success, "" }; - } catch (sql::SQLException& e) { - return_value = { nullptr, execute_result::sql_error, e.what() }; - } - delete stmt; - - return return_value; -} - -bool -db_connection::is_connected() { - if (this->connection == nullptr) return false; - - // check if our connection is always valid - if (this->connection->isClosed() || not this->connection->isValid()) { - LOG_INFO_("MySQL database connection is either closed or invalid, try to reconnect.", - "db_connection"); - this->connection->reconnect(); - if (this->connection->isClosed() || not this->connection->isValid()) { - this->connected = false; - LOG_ERR_("Unable to reconnect to MySQL.", "db_connection"); - } - } - return this->connected; -} - -empty_result -db_connection::create_database() { - auto query = tool::fmt(this->create_database_query, this->db_name.c_str()); - return this->execute(query); -} - -} // mysql - -} // cameradar - -} // etix diff --git a/cache_managers/mysql_cache_manager/src/mysql_cache_manager.cpp b/cache_managers/mysql_cache_manager/src/mysql_cache_manager.cpp deleted file mode 100644 index 0c3cec6..0000000 --- a/cache_managers/mysql_cache_manager/src/mysql_cache_manager.cpp +++ /dev/null @@ -1,292 +0,0 @@ -// Copyright 2016 Etix Labs -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include - -/* DATA FORMAT -** -** Example : -** -** "address" : "173.16.100.45", -** "ids_found" : true, -** "password" : "123456", -** "path_found" : true, -** "port" : 554, -** "product" : "Vivotek FD9381-HTV", -** "protocol" : "tcp", -** "route" : "/live.sdp", -** "service_name" : "rtsp", -** "state" : "open", -** "thumbnail_path" : "/tmp/127.0.0.1/1463735257.jpg", -** "username" : "admin" -** -*/ - -namespace etix { - -namespace cameradar { - -const std::string mysql_cache_manager::create_table_query = - "CREATE TABLE IF NOT EXISTS `cameradar_results` (" - "`id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT, " - "`address` tinytext NOT NULL, " - "`password` tinytext NOT NULL, " - "`product` tinytext NOT NULL, " - "`protocol` tinytext NOT NULL, " - "`route` tinytext NOT NULL, " - "`service_name` tinytext NOT NULL, " - "`state` tinytext NOT NULL, " - "`thumbnail_path` tinytext NOT NULL, " - "`username` tinytext NOT NULL, " - "`port` int(11) UNSIGNED NOT NULL, " - "`ids_found` tinytext NOT NULL, " - "`path_found` tinytext NOT NULL, " - "PRIMARY KEY (`id`));"; - -const std::string mysql_cache_manager::insert_with_id_query = - "INSERT INTO `%s`.`cameradar_results`" - " (`address`, `password`, `product`, `protocol`, `route`, `service_name`, `state`, " - "`thumbnail_path`, `username`, `port`, `ids_found`, `path_found`)" - " VALUES ('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s')"; - -const std::string mysql_cache_manager::update_result_query = - "UPDATE `%s`.`cameradar_results` SET" - " `cameradar_results`.`address` = '%s'," - " `cameradar_results`.`password` = '%s'," - " `cameradar_results`.`product` = '%s'," - " `cameradar_results`.`protocol` = '%s'," - " `cameradar_results`.`route` = '%s'," - " `cameradar_results`.`service_name` = '%s'," - " `cameradar_results`.`state` = '%s'," - " `cameradar_results`.`thumbnail_path` = '%s'," - " `cameradar_results`.`username` = '%s'," - " `cameradar_results`.`port` = '%s'," - " `cameradar_results`.`ids_found` = '%s'," - " `cameradar_results`.`path_found` = '%s'" - " WHERE `cameradar_results`.`address` LIKE '%s'"; - -const std::string mysql_cache_manager::exist_query = - "SELECT * FROM `%s`.`cameradar_results` WHERE `cameradar_results`.`address` = '%s'"; - -const std::string mysql_cache_manager::get_results_query = "SELECT * FROM `%s`.`cameradar_results`"; - -const std::string mysql_cache_manager::name = "mysql-cache-manager"; - -mysql_cache_manager::~mysql_cache_manager() {} - -const std::string& -mysql_cache_manager::get_name() const { - return mysql_cache_manager::static_get_name(); -} - -const std::string& -mysql_cache_manager::static_get_name() { - return mysql_cache_manager::name; -} - -bool -mysql_cache_manager::configure(std::shared_ptr configuration) { - return this->load_mysql_conf(configuration); -} - -bool -mysql_cache_manager::execute_query(const std::string& query) { - auto check_err = [](const auto& res) { - if (res.state == mysql::execute_result::sql_error) { - LOG_WARN_(res.error_msg, "mysql_cache_manager"); - return false; - } - return true; - }; - return check_err(this->connection.execute(query)); -} - -bool -mysql_cache_manager::load_mysql_conf( - std::shared_ptr configuration) { - this->configuration = configuration; - - try { - this->db_conf.host = configuration->raw_conf["mysql_db"]["host"].asString(); - this->db_conf.port = configuration->raw_conf["mysql_db"]["port"].asUInt(); - this->db_conf.user = configuration->raw_conf["mysql_db"]["user"].asString(); - this->db_conf.password = configuration->raw_conf["mysql_db"]["password"].asString(); - this->db_conf.db_name = configuration->raw_conf["mysql_db"]["db_name"].asString(); - } catch (const std::exception& e) { - LOG_ERR_("Configuration of the MySQL db failed : " + std::string(e.what()), - "mysql_cache_manager"); - return false; - } - - if (not this->connection - .connect(db_conf.host + ":" + std::to_string(db_conf.port), - db_conf.user, - db_conf.password, - db_conf.db_name) - .first) { - LOG_ERR_("Configuration of the MySQL DB failed", "mysql_cache_manager"); - return false; - } - - // Tries to create the Result table in the DB and returns the success state - return (execute_query(create_table_query)); -} - -//! Replaces all cached streams by the content of the vector given as -//! parameter -void -mysql_cache_manager::set_streams(std::vector models) { - LOG_DEBUG_("Beginning stream list DB insertion", "mysql_cache_manager"); - std::lock_guard lock(m); - for (const auto& model : models) { - if (!model.service_name.compare("rtsp") && !model.state.compare("open")) { - auto query = tool::fmt( - this->exist_query, this->connection.get_db_name().c_str(), model.address.c_str()); - auto result = this->connection.query(query); - - if (result.data->next()) continue; - - query = tool::fmt(this->insert_with_id_query, - this->connection.get_db_name().c_str(), - model.address.c_str(), - model.password.c_str(), - model.product.c_str(), - model.protocol.c_str(), - model.route.c_str(), - model.service_name.c_str(), - model.state.c_str(), - model.thumbnail_path.c_str(), - model.username.c_str(), - std::to_string(model.port).c_str(), - std::to_string(model.ids_found).c_str(), - std::to_string(model.path_found).c_str()); - execute_query(query); - } - } -} - -//! Inserts a single stream to the cache -void -mysql_cache_manager::update_stream(const etix::cameradar::stream_model& model) { - auto query = tool::fmt(this->update_result_query, - this->connection.get_db_name().c_str(), - model.address.c_str(), - model.password.c_str(), - model.product.c_str(), - model.protocol.c_str(), - model.route.c_str(), - model.service_name.c_str(), - model.state.c_str(), - model.thumbnail_path.c_str(), - model.username.c_str(), - std::to_string(model.port).c_str(), - std::to_string(model.ids_found).c_str(), - std::to_string(model.path_found).c_str(), - model.address.c_str()); - std::lock_guard lock(m); - execute_query(query); -} - -//! Gets all cached streams -std::vector -mysql_cache_manager::get_streams() { - auto query = tool::fmt(this->get_results_query, this->connection.get_db_name().c_str()); - auto result = this->connection.query(query); - - if (not result.data) { - delete result.data; - return {}; - } - - std::vector lst; - while (result.data->next()) { - // If it's an open RTSP stream - if (not result.data->getString("state").compare("open") && - not result.data->getString("service_name").compare("rtsp")) { - stream_model s{ - result.data->getString("address"), result.data->getUInt("port"), - result.data->getString("username"), result.data->getString("password"), - result.data->getString("route"), result.data->getString("service_name"), - result.data->getString("product"), result.data->getString("protocol"), - result.data->getString("state"), result.data->getBoolean("path_found"), - result.data->getBoolean("ids_found"), result.data->getString("thumbnail_path") - }; - lst.push_back(s); - } - } - - delete result.data; - return lst; -} - -//! Gets all valid streams -std::vector -mysql_cache_manager::get_valid_streams() { - auto query = tool::fmt(this->get_results_query, this->connection.get_db_name().c_str()); - auto result = this->connection.query(query); - - if (not result.data) { - delete result.data; - return {}; - } - - std::vector lst; - while (result.data->next()) { - // If the ID and the Path were found add this stream - if (not result.data->getString("ids_found").compare("1") && - not result.data->getString("path_found").compare("1")) { - stream_model s{ - result.data->getString("address"), result.data->getUInt("port"), - result.data->getString("username"), result.data->getString("password"), - result.data->getString("route"), result.data->getString("service_name"), - result.data->getString("product"), result.data->getString("protocol"), - result.data->getString("state"), result.data->getBoolean("path_found"), - result.data->getBoolean("ids_found"), result.data->getString("thumbnail_path") - }; - lst.push_back(s); - } - } - - delete result.data; - return lst; -} - -// Returns true if the stream passed as a parameter has changed in the cache -bool -mysql_cache_manager::has_changed(const etix::cameradar::stream_model& old) { - auto query = tool::fmt(this->get_results_query, this->connection.get_db_name().c_str()); - auto result = this->connection.query(query); - - if (not result.data) { - delete result.data; - return {}; - } - - while (result.data->next()) { - if (result.data->getString("address") == old.address) - if (result.data->getBoolean("ids_found") != old.ids_found || - result.data->getBoolean("path_found") != old.path_found) - return true; - } - return false; -} - -extern "C" { -cache_manager_iface* -cache_manager_instance_new() { - return new mysql_cache_manager(); -} -} -} -} diff --git a/cameraccess/main.go b/cameraccess/main.go new file mode 100644 index 0000000..3362ce0 --- /dev/null +++ b/cameraccess/main.go @@ -0,0 +1,106 @@ +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "fmt" + "os" + "time" + + "github.com/EtixLabs/cameradar/cameradar" + "github.com/fatih/color" + "github.com/jessevdk/go-flags" +) + +type options struct { + Target string `short:"t" long:"target" description:"The target on which to scan for open RTSP streams - required" required:"true"` + Ports string `short:"p" long:"ports" description:"The ports on which to search for RTSP streams" default:"554,8554"` + OutputFile string `short:"o" long:"nmap-output" description:"The path where nmap will create its XML result file" default:"/tmp/cameradar_scan.xml"` + Routes string `short:"r" long:"custom-routes" description:"The path on which to load a custom routes dictionary" default:"./dictionaries/routes"` + Credentials string `short:"c" long:"custom-credentials" description:"The path on which to load a custom credentials JSON dictionary" default:"./dictionaries/credentials.json"` + Speed int `short:"s" long:"speed" description:"The nmap speed preset to use" default:"4"` + Timeout int `short:"T" long:"timeout" description:"The timeout in miliseconds to use for attack attempts" default:"1000"` + EnableLogs bool `short:"l" long:"log" description:"Enable the logs for nmap's output to stdout"` +} + +func main() { + var options options + _, err := flags.ParseArgs(&options, os.Args[1:]) + if err != nil { + os.Exit(0) + } + + credentials, err := cmrdr.LoadCredentials(options.Credentials) + if err != nil { + color.Red("Invalid credentials dictionary: %s", err.Error()) + return + } + + routes, err := cmrdr.LoadRoutes(options.Routes) + if err != nil { + color.Red("Invalid routes dictionary: %s", err.Error()) + return + } + + streams, _ := cmrdr.Discover(options.Target, options.Ports, options.OutputFile, options.Speed, options.EnableLogs) + streams, _ = cmrdr.AttackRoute(streams, routes, time.Duration(options.Timeout)*time.Millisecond, options.EnableLogs) + streams, _ = cmrdr.AttackCredentials(streams, credentials, time.Duration(options.Timeout)*time.Millisecond, options.EnableLogs) + + prettyPrint(streams) +} + +func prettyPrint(streams []cmrdr.Stream) { + yellow := color.New(color.FgYellow, color.Bold, color.Underline).SprintFunc() + blue := color.New(color.FgBlue, color.Underline).SprintFunc() + green := color.New(color.FgGreen, color.Bold).SprintFunc() + red := color.New(color.FgRed, color.Bold).SprintFunc() + white := color.New(color.Italic).SprintFunc() + + success := 0 + + if len(streams) > 0 { + for _, stream := range streams { + if stream.CredentialsFound && stream.RouteFound { + fmt.Printf("%s\tDevice RTSP URL:\t%s\n", green("\xE2\x96\xB6"), blue(cmrdr.RTSPURL(stream))) + success++ + } else { + fmt.Printf("%s\tAdmin panel URL:\t%s %s\n", red("\xE2\x96\xB6"), yellow(cmrdr.AdminPanelURL(stream)), white("You can use this URL to try attacking the camera's admin panel instead.")) + } + + fmt.Printf("\tDevice model:\t\t%s\n\n", stream.Device) + fmt.Printf("\tIP address:\t\t%s\n", stream.Address) + fmt.Printf("\tRTSP port:\t\t%d\n", stream.Port) + if stream.CredentialsFound { + fmt.Printf("\tUsername:\t\t%s\n", green(stream.Username)) + fmt.Printf("\tPassword:\t\t%s\n", green(stream.Password)) + } else { + fmt.Printf("\tUsername:\t\t%s\n", red("not found")) + fmt.Printf("\tPassword:\t\t%s\n", red("not found")) + } + if stream.RouteFound { + fmt.Printf("\tRTSP route:\t\t%s\n\n\n", green("/"+stream.Route)) + } else { + fmt.Printf("\tRTSP route:\t\t%s\n\n\n", red("not found")) + } + } + if success > 1 { + fmt.Printf("%s Successful attack: %s devices were accessed", green("\xE2\x9C\x94"), green(len(streams))) + } else if success == 1 { + fmt.Printf("%s Successful attack: %s device was accessed", green("\xE2\x9C\x94"), green(len(streams))) + } else { + fmt.Printf("%s Streams were found but none were accessed. They are most likely configured with secure credentials and routes. You can try adding entries to the dictionary or generating your own in order to attempt a bruteforce attack on the cameras.", red("\xE2\x9C\x96")) + } + } else { + fmt.Printf("%s No streams were found. Please make sure that your target is on an accessible network.", red("\xE2\x9C\x96")) + } +} diff --git a/cameradar/attack.go b/cameradar/attack.go new file mode 100644 index 0000000..4934e9d --- /dev/null +++ b/cameradar/attack.go @@ -0,0 +1,232 @@ +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package cmrdr + +import ( + "fmt" + "time" + + curl "github.com/andelf/go-curl" + "github.com/pkg/errors" + v "gopkg.in/go-playground/validator.v9" +) + +// HACK: See https://stackoverflow.com/questions/3572397/lib-curl-in-c-disable-printing +func doNotWrite([]uint8, interface{}) bool { + return true +} + +func routeAttack(camera Stream, route string, timeout time.Duration, enableLogs bool) bool { + easy := curl.EasyInit() + defer easy.Cleanup() + + if easy != nil { + attackURL := fmt.Sprintf( + "rtsp://%s:%s@%s:%d/%s", + camera.Username, + camera.Password, + camera.Address, + camera.Port, + route, + ) + + if enableLogs { + // Debug logs when logs are enabled + easy.Setopt(curl.OPT_VERBOSE, 1) + } else { + // Do not write sdp in stdout + easy.Setopt(curl.OPT_WRITEFUNCTION, doNotWrite) + } + + // Do not send a body in the describe request + easy.Setopt(curl.OPT_NOBODY, 1) + // Send a request to the URL of the camera we want to attack + easy.Setopt(curl.OPT_URL, attackURL) + // Set the RTSP STREAM URI as the camera URL + easy.Setopt(curl.OPT_RTSP_STREAM_URI, attackURL) + // 2 is CURL_RTSPREQ_DESCRIBE + easy.Setopt(curl.OPT_RTSP_REQUEST, 2) + // Set custom timeout + easy.Setopt(curl.OPT_TIMEOUT_MS, int(timeout/time.Millisecond)) + + // Perform the request + easy.Perform() + + // Get return code for the request + rc, err := easy.Getinfo(curl.INFO_RESPONSE_CODE) + if err != nil { + return false + } + + // If it's a 404, it means that the route was not valid + if rc == 404 { + return false + } + + return true + } + return false +} + +func credAttack(camera Stream, username string, password string, timeout time.Duration, enableLogs bool) bool { + easy := curl.EasyInit() + defer easy.Cleanup() + + if easy != nil { + attackURL := fmt.Sprintf( + "rtsp://%s:%s@%s:%d/%s", + username, + password, + camera.Address, + camera.Port, + camera.Route, + ) + + if enableLogs { + // Debug logs when logs are enabled + easy.Setopt(curl.OPT_VERBOSE, 1) + } else { + // Do not write sdp in stdout + easy.Setopt(curl.OPT_WRITEFUNCTION, doNotWrite) + } + + // Do not send a body in the describe request + easy.Setopt(curl.OPT_NOBODY, 1) + // Send a request to the URL of the camera we want to attack + easy.Setopt(curl.OPT_URL, attackURL) + // Set the RTSP STREAM URI as the camera URL + easy.Setopt(curl.OPT_RTSP_STREAM_URI, attackURL) + // 2 is CURL_RTSPREQ_DESCRIBE + easy.Setopt(curl.OPT_RTSP_REQUEST, 2) + // Set custom timeout + easy.Setopt(curl.OPT_TIMEOUT_MS, int(timeout/time.Millisecond)) + + // Perform the request + easy.Perform() + + // Get return code for the request + rc, err := easy.Getinfo(curl.INFO_RESPONSE_CODE) + if err != nil { + return false + } + + // If it's a 403 or a 401, it means that the credentials are not correct + if rc == 403 || rc == 401 { + return false + } + + return true + } + return false +} + +func attackCameraCredentials(target Stream, credentials Credentials, resultsChan chan<- Stream, timeout time.Duration, log bool) { + for _, username := range credentials.Usernames { + for _, password := range credentials.Passwords { + ok := credAttack(target, username, password, timeout, log) + if ok { + target.CredentialsFound = true + target.Username = username + target.Password = password + resultsChan <- target + return + } + } + } + target.CredentialsFound = false + resultsChan <- target +} + +func attackCameraRoute(target Stream, routes Routes, resultsChan chan<- Stream, timeout time.Duration, log bool) { + for _, route := range routes { + ok := routeAttack(target, route, timeout, log) + if ok { + target.RouteFound = true + target.Route = route + resultsChan <- target + return + } + } + target.RouteFound = false + resultsChan <- target +} + +// AttackCredentials attempts to guess the provided targets' credentials using the given +// dictionary or the default dictionary if none was provided by the user +func AttackCredentials(targets []Stream, credentials Credentials, timeout time.Duration, log bool) (results []Stream, err error) { + attacks := make(chan Stream) + defer close(attacks) + + validate := v.New() + for _, target := range targets { + err := validate.Struct(target) + if err != nil { + return targets, errors.Wrap(err, "invalid streams") + } + + go attackCameraCredentials(target, credentials, attacks, timeout, log) + } + + attackResults := []Stream{} + for _ = range targets { + attackResults = append(attackResults, <-attacks) + } + + found := 0 + for _, result := range attackResults { + if result.CredentialsFound == true { + targets = replace(targets, result) + found++ + } + } + if found == 0 { + return targets, errors.New("No credentials found") + } + + return targets, nil +} + +// AttackRoute attempts to guess the provided targets' streaming routes using the given +// dictionary or the default dictionary if none was provided by the user +func AttackRoute(targets []Stream, routes Routes, timeout time.Duration, log bool) (results []Stream, err error) { + attacks := make(chan Stream) + defer close(attacks) + + validate := v.New() + for _, target := range targets { + err := validate.Struct(target) + if err != nil { + return targets, errors.Wrap(err, "invalid streams") + } + + go attackCameraRoute(target, routes, attacks, timeout, log) + } + + attackResults := []Stream{} + for _ = range targets { + attackResults = append(attackResults, <-attacks) + } + + found := 0 + for _, result := range attackResults { + if result.RouteFound == true { + targets = replace(targets, result) + found++ + } + } + if found == 0 { + return targets, errors.New("No routes found") + } + + return targets, nil +} diff --git a/cameradar/discover.go b/cameradar/discover.go new file mode 100644 index 0000000..6f28ed5 --- /dev/null +++ b/cameradar/discover.go @@ -0,0 +1,152 @@ +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package cmrdr + +import ( + "bufio" + "encoding/xml" + "fmt" + "io/ioutil" + "log" + "os/exec" + + "github.com/pkg/errors" + v "gopkg.in/go-playground/validator.v9" +) + +// These constants detail the different level of nmap speed presets +// that determine the timeout values and wether or not nmap makes use of parallelism +const ( + // PARANOID NO PARALLELISM | 5min timeout | 100ms to 10s round-trip time timeout | 5mn scan delay + PARANOIAC = 0 + // SNEAKY NO PARALLELISM | 15sec timeout | 100ms to 10s round-trip time timeout | 15s scan delay + SNEAKY = 1 + // POLITE NO PARALLELISM | 1sec timeout | 100ms to 10s round-trip time timeout | 400ms scan delay + POLITE = 2 + // NORMAL PARALLELISM | 1sec timeout | 100ms to 10s round-trip time timeout | 0s scan delay + NORMAL = 3 + // AGGRESSIVE PARALLELISM | 500ms timeout | 100ms to 1250ms round-trip time timeout | 0s scan delay + AGGRESSIVE = 4 + // INSANE PARALLELISM | 250ms timeout | 50ms to 300ms round-trip time timeout | 0s scan delay + INSANE = 5 +) + +// RunNmap runs nmap on the specified targets's specified ports, using the given nmap speed +func RunNmap(targets, ports string, resultFilePath string, nmapSpeed int, enableLogs bool) error { + // Prepare nmap command + cmd := exec.Command( + "nmap", + fmt.Sprintf("-T%d", nmapSpeed), + "-A", + targets, + "-p", + ports, + "-oX", + resultFilePath, + ) + + // Pipe stdout to be able to write the logs in realtime + stdout, err := cmd.StdoutPipe() + if err != nil { + return errors.Wrap(err, "Couldn't get stdout pipe") + } + + // Execute the nmap command + if err := cmd.Start(); err != nil { + return errors.Wrap(err, "Coudln't run nmap command") + } + + // Scan the pipe until an end of file or an error occurs + in := bufio.NewScanner(stdout) + for in.Scan() { + if enableLogs { + log.Printf(in.Text()) + } + } + if err := in.Err(); err != nil { + if enableLogs { + log.Printf("error: %s", err) + } + } + + return nil +} + +// ParseNmapResult returns a slice of streams from an NMap XML result file +// To generate one yourself, use the -X option when running NMap +func ParseNmapResult(nmapResultFilePath string) ([]Stream, error) { + var streams []Stream + + // Open & Read XML file + content, err := ioutil.ReadFile(nmapResultFilePath) + if err != nil { + return streams, errors.Wrap(err, "Could not read nmap result file at "+nmapResultFilePath+":") + } + + // Unmarshal content of XML file into data structure + result := &NmapResult{} + err = xml.Unmarshal(content, &result) + if err != nil { + return streams, err + } + + // Iterate on hosts to try to find hosts with ports that + // - serve RTSP + // - are open + validate := v.New() + for _, host := range result.Hosts { + if host.Ports.Ports == nil { + continue + } + for _, port := range host.Ports.Ports { + err = validate.Struct(port) + if err != nil { + continue + } + streams = append(streams, Stream{ + Device: port.Service.Product, + Address: host.Address.Addr, + Port: port.PortID, + }) + } + } + + return streams, nil +} + +// Discover scans the target networks and tries to find RTSP streams within them +// targets - string: The addresses +// - a subnet (e.g.: 172.16.100.0/24) +// - an IP (e.g.: 172.16.100.10) +// - a hostname (e.g.: localhost) +// - a range of IPs (e.g.: 172.16.100.10-172.16.100.20) +// - a mix of all those separated by commas (e.g.: localhost,172.17.100.0/24,172.16.100.10-172.16.100.20,0.0.0.0). +// ports - string : +// - one or multiple ports and port ranges separated by commas (e.g.: 554,8554-8560,18554-28554) +func Discover(targets string, ports string, nmapResultPath string, speed int, log bool) ([]Stream, error) { + var streams []Stream + + // Run nmap command to discover open ports on the specified targets & ports + err := RunNmap(targets, ports, nmapResultPath, speed, log) + if err != nil { + return streams, err + } + + // Get found streams from nmap results + streams, err = ParseNmapResult(nmapResultPath) + if err != nil { + return streams, err + } + + return streams, nil +} diff --git a/cameradar/helpers.go b/cameradar/helpers.go new file mode 100644 index 0000000..1af81c0 --- /dev/null +++ b/cameradar/helpers.go @@ -0,0 +1,38 @@ +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package cmrdr + +import "fmt" + +func replace(streams []Stream, new Stream) []Stream { + updatedSlice := streams[:0] + + for _, old := range streams { + if old.Address == new.Address && old.Port == new.Port { + updatedSlice = append(updatedSlice, new) + } else { + updatedSlice = append(updatedSlice, old) + } + } + return updatedSlice +} + +// RTSPURL generates a stream's RTSP URL +func RTSPURL(stream Stream) string { + return "rtsp://" + stream.Username + ":" + stream.Password + "@" + stream.Address + ":" + fmt.Sprint(stream.Port) + "/" + stream.Route +} + +// AdminPanelURL returns the URL to the camera's admin panel +func AdminPanelURL(stream Stream) string { + return "http://" + stream.Address + "/" +} diff --git a/cameradar/loaders.go b/cameradar/loaders.go new file mode 100644 index 0000000..5b88101 --- /dev/null +++ b/cameradar/loaders.go @@ -0,0 +1,58 @@ +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package cmrdr + +import ( + "bufio" + "encoding/json" + "io/ioutil" + "os" + + "github.com/pkg/errors" +) + +// LoadCredentials opens a dictionary file and returns its contents as a Credentials structure +func LoadCredentials(path string) (Credentials, error) { + var creds Credentials + + // Open & Read XML file + content, err := ioutil.ReadFile(path) + if err != nil { + return creds, errors.Wrap(err, "Could not read credentials dictionary file at "+path+":") + } + + // Unmarshal content of JSON file into data structure + err = json.Unmarshal(content, &creds) + if err != nil { + return creds, err + } + + return creds, nil +} + +// LoadRoutes opens a dictionary file and returns its contents as a Routes structure +func LoadRoutes(path string) (Routes, error) { + file, err := os.Open(path) + if err != nil { + return nil, err + } + defer file.Close() + + var routes Routes + scanner := bufio.NewScanner(file) + for scanner.Scan() { + routes = append(routes, scanner.Text()) + } + + return routes, scanner.Err() +} diff --git a/cameradar/models.go b/cameradar/models.go new file mode 100644 index 0000000..4c9654f --- /dev/null +++ b/cameradar/models.go @@ -0,0 +1,38 @@ +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package cmrdr + +// Stream represents a camera's RTSP stream +type Stream struct { + Device string + Username string + Password string + Route string + Address string `validate:"required"` + Port uint `validate:"required"` + + CredentialsFound bool + RouteFound bool +} + +// Credentials is a map of credentials +// usernames are keys and passwords are values +// creds['admin'] -> 'secure_password' +type Credentials struct { + Usernames []string `json:"usernames"` + Passwords []string `json:"passwords"` +} + +// Routes is a slice of Routes +// ['/live.sdp', '/media.amp', ...] +type Routes []string diff --git a/cameradar/xml_models.go b/cameradar/xml_models.go new file mode 100644 index 0000000..d3d25a5 --- /dev/null +++ b/cameradar/xml_models.go @@ -0,0 +1,62 @@ +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package cmrdr + +import "encoding/xml" + +// NmapResult is the structure that holds all the information from an NMap scan +type NmapResult struct { + XMLName xml.Name `xml:"nmaprun"` + Hosts []Host `xml:"host" validate:"required"` +} + +// Host represents a host discovered during a scan +type Host struct { + XMLName xml.Name `xml:"host"` + Address Address `xml:"address"` + Ports Ports `xml:"ports"` +} + +// Address is a host's address discovered during a scan +type Address struct { + XMLName xml.Name `xml:"address"` + Addr string `xml:"addr,attr"` + AddrType string `xml:"addrType,attr"` +} + +// Ports is the list of openned ports on a host +type Ports struct { + XMLName xml.Name `xml:"ports"` + Ports []Port `xml:"port"` +} + +// Port is a port found on a host during a scan +type Port struct { + XMLName xml.Name `xml:"port"` + PortID uint `xml:"portid,attr"` + State State `xml:"state"` + Service Service `xml:"service"` +} + +// State is the state of a port +type State struct { + XMLName xml.Name `xml:"state"` + State string `xml:"state,attr" validate:"required,eq=open"` +} + +// Service represents the service that a port provides +type Service struct { + XMLName xml.Name `xml:"service"` + Name string `xml:"name,attr" validate:"required,eq=rtsp"` + Product string `xml:"product,attr"` +} diff --git a/cameradar_standalone/CMakeLists.txt b/cameradar_standalone/CMakeLists.txt deleted file mode 100644 index b122c95..0000000 --- a/cameradar_standalone/CMakeLists.txt +++ /dev/null @@ -1,60 +0,0 @@ -## Copyright 2016 Etix Labs -## -## Licensed under the Apache License, Version 2.0 (the "License"); -## you may not use this file except in compliance with the License. -## You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. - -cmake_minimum_required (VERSION 2.8.1) -cmake_policy(SET CMP0048 OLD) - -project(cameradar CXX) - -# find gstreamer 1.x libraries -include(FindPkgConfig) - -pkg_search_module(GSTREAMER REQUIRED gstreamer-1.0) -find_library(LIB_GSTREAMER NAMES ${GSTREAMER_LIBRARIES} HINTS ${GSTREAMER_LIBRARY_DIRS}) - -include_directories ( - ${GSTREAMER_INCLUDE_DIRS} - ${PROJECT_SOURCE_DIR}/include - ${VERSION_INCLUDE_DIR} -) - -link_directories ( - ${GSTREAMER_LIBRARY_DIRS} - "../deps/jsoncpp/src/deps.jsoncpp/src/lib_json" -) - -if ("${CMAKE_C_COMPILER_ID}" STREQUAL "Clang") - # search special osx gstreamer libs - pkg_search_module(GSTREAMER_APP REQUIRED gstreamer-app-1.0) - find_library(LIB_GSTREAMER NAMES ${GSTREAMER_APP_LIBRARIES} HINTS ${GSTREAMER_APP_LIBRARY_DIRS}) - - include_directories (${GSTREAMER_APP_INCLUDE_DIRS}) - - link_directories (${GSTREAMER_APP_LIBRARY_DIRS}) -endif() - -include (find_sources) -find_sources ("src" "include" "src/tasks") - -add_executable (cameradar ${SOURCES}) -target_link_libraries (cameradar pthread jsoncpp dl curl ${GSTREAMER_LIBRARIES}) - -# Add the conf files to the build dir -add_custom_command(TARGET cameradar PRE_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_directory - ${CMAKE_SOURCE_DIR}/cameradar_standalone/conf $/conf/) - -set (BINARIES_NAME ${PROJECT_BINARY_DIR}/cameradar) -list (APPEND CAMERADAR_BINARIES ${BINARIES_NAME}) -set (CAMERADAR_BINARIES ${CAMERADAR_BINARIES} PARENT_SCOPE) diff --git a/cameradar_standalone/conf/cameradar.conf.json b/cameradar_standalone/conf/cameradar.conf.json deleted file mode 100644 index 86f7308..0000000 --- a/cameradar_standalone/conf/cameradar.conf.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "mysql_db" : { - "host" : "cameradar-database", - "port" : 3306, - "user": "root", - "password": "root", - "db_name": "cmrdr" - }, - "target" : "localhost", - "ports" : "554,8554", - "rtsp_url_file" : "/cameradar/conf/url.json", - "rtsp_ids_file" : "/cameradar/conf/ids.json", - "thumbnail_storage_path" : "/tmp/thumbs", - "cache_manager_path" : "/cameradar/cache_managers", - "cache_manager_name" : "dumb" -} diff --git a/cameradar_standalone/conf/ids.json b/cameradar_standalone/conf/ids.json deleted file mode 100644 index 046b60c..0000000 --- a/cameradar_standalone/conf/ids.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "username": [ - "", - "admin", - "Admin", - "root", - "supervisor", - "ubnt" - ], - "password" : [ - "", - "admin", - "9999", - "123456", - "pass", - "camera", - "1234", - "12345", - "fliradmin", - "system", - "jvc", - "meinsm", - "root", - "4321", - "1111111", - "password", - "ikwd", - "supervisor", - "ubnt" - ] -} \ No newline at end of file diff --git a/cameradar_standalone/conf/url.json b/cameradar_standalone/conf/url.json deleted file mode 100644 index 23af730..0000000 --- a/cameradar_standalone/conf/url.json +++ /dev/null @@ -1,117 +0,0 @@ -{ - "urls" : [ - "/", - "/1.AMP", - "/1/stream1", - "/CAM_ID.password.mp2", - "/GetData.cgi", - "/MediaInput/h264", - "/MediaInput/mpeg4", - "/VideoInput/1/h264/1", - "/access_code", - "/access_name_for_stream_1_to_5", - "/av0_0", - "/av2", - "/avn=2", - "/axis-media/media.amp", - "/cam", - "/cam0_0", - "/cam0_1", - "/cam1/h264", - "/cam1/h264/multicast", - "/cam1/mjpeg", - "/cam1/mpeg4", - "/camera.stm", - "/ch0", - "/ch001.sdp", - "/ch01.264", - "/ch0_unicast_firststream", - "/ch0_unicast_secondstream", - "/channel1", - "/h264", - "/h264/media.amp", - "/image.mpg", - "/img/media.sav", - "/img/video.asf", - "/img/video.sav", - "/ioImage/1", - "/ipcam.sdp", - "/ipcam_h264.sdp", - "/live.sdp", - "/live/h264", - "/live/mpeg4", - "/live_mpeg4.sdp", - "/livestream", - "/livestream/", - "/media/media.amp", - "/media/video1", - "/mjpeg/media.smp", - "/mp4", - "/mpeg4", - "/mpeg4/1/media.amp", - "/mpeg4/media.amp", - "/mpeg4/media.smp", - "/mpeg4unicast", - "/mpg4/rtsp.amp", - "/multicaststream", - "/now.mp4", - "/nph-h264.cgi", - "/nphMpeg4/g726-640x", - "/nphMpeg4/g726-640x480", - "/nphMpeg4/nil-320x240", - "/play1.sdp", - "/play2.sdp", - "/rtpvideo1.sdp", - "/rtsp_live0", - "/rtsp_live1", - "/rtsp_live2", - "/rtsp_tunnel", - "/rtsph264", - "/stream1", - "/user.pin.mp2", - "/user_defined", - "/video", - "/video.3gp", - "/video.mp4", - "/video1", - "/video1+audio1", - "/vis", - "/wfov", - "/video.h264", - "/11", - "/12", - "/ch1-s1", - "/live3.sdp", - "/onvif-media/media.amp", - "/axis-media/media.amp", - "/axis-media/media.amp?videocodec=h264", - "/mpeg4/media.amp", - "/stream", - "/cam/realmonitor", - "/live", - "/video.pro2", - "/videoMain", - "/VideoInput/1/mpeg4/1", - "/VideoInput/1/h264/1", - "/video.pro3", - "/video.pro1", - "/video.mjpg", - "/h264_vga.sdp", - "/media.amp", - "/media", - "/ONVIF/MediaInput", - "/nphMpeg4/g726-640x48", - "/MediaInput/mpeg4", - "/MediaInput/h264", - "/Streaming/Channels/1", - "/ch0_0.h264", - "/rtsph2641080p", - "/live/av0", - "/cam1/onvif-h264", - "/ucast/11", - "/LowResolutionVideo", - "/1", - "/live/ch00_0", - "/medias2" - ] -} diff --git a/cameradar_standalone/include/cachemanager.h b/cameradar_standalone/include/cachemanager.h deleted file mode 100644 index d077ff4..0000000 --- a/cameradar_standalone/include/cachemanager.h +++ /dev/null @@ -1,185 +0,0 @@ -// Copyright 2016 Etix Labs -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -#include -#include -#include -#include -#include - -namespace etix { -namespace cameradar { - -// The interface a cache_manager should implement to be valid -class cache_manager_iface { -public: - virtual ~cache_manager_iface() {} - - // Launches the manager configuration - // \return false if failed - virtual bool configure(std::shared_ptr configuration) = 0; - - // get the name of the cache manager - virtual const std::string& get_name() const = 0; - - // Replaces all cached streams by the content of the vector given as - // parameter - virtual void set_streams(std::vector model) = 0; - - // Inserts a single stream to the cache - virtual void update_stream(const etix::cameradar::stream_model& newmodel) = 0; - - // Returns true if the stream passed as a parameter has changed in the cache - virtual bool has_changed(const etix::cameradar::stream_model&) = 0; - - // Gets all cached streams - virtual std::vector get_streams() = 0; - - // Gets all valid streams which have been accessed - virtual std::vector get_valid_streams() = 0; -}; - -class cache_manager_base : public cache_manager_iface { -public: - cache_manager_base() = default; - virtual ~cache_manager_base() = default; - - // Launches the cache manager configuration - // \return false if failed - virtual bool configure(std::shared_ptr configuration) = 0; - - // get the name of the cache manager - virtual const std::string& get_name() const = 0; - - // Replaces all cached streams by the content of the vector given as - // parameter - virtual void set_streams(std::vector model) = 0; - - // Returns true if the stream passed as a parameter has changed in the cache - virtual bool has_changed(const etix::cameradar::stream_model&) = 0; - - // Updates a single stream to the cache - virtual void update_stream(const etix::cameradar::stream_model& newmodel) = 0; - - // Gets all cached streams - virtual std::vector get_streams() = 0; - - // Gets all valid streams which have been accessed - virtual std::vector get_valid_streams() = 0; - - // Get the manager's instance - cache_manager_base& get_instance(); - - template - std::shared_ptr - get() { - static_assert(std::is_base_of::value, - "I must implement cache_manager_base"); - std::shared_ptr cache_manager(dynamic_cast(this)); - if (not cache_manager) return nullptr; - return cache_manager->template get(); - } -}; - -// The representation of a cache manager -// -// This class loads a shared library, and tries to call an extern "C" -// function which should instanciate a new instance of the plugin. -class cache_manager { -private: - static const std::string PLUGIN_EXT; - static const std::string default_symbol; - - // The name of the cache manager - std::string name; - - // The write mutex to avoid conflicts when multithreading - std::mutex m; - - // The path where the manager is located - // should be specified in the configuration file - std::string path; - - // The symbol entry point of the manager to - // call to create an instance from the shared library - std::string symbol; - - // The handle to the shared library where is stored the manager - void* handle = nullptr; - - // The cache manager instance if it is successfully loaded - cache_manager_iface* ptr = nullptr; - - // Internal function that creates the full path of the cache manager - // - // full path is composed of: the path, the name, the string "_cache-manager" - // and the extension PLUGIN_EXT depending of the platform - std::string make_full_path(); - -public: - // Delete constructor - cache_manager() = delete; - - // The manager needs a path and a symbol to be instantiated. - // The symbol can be changed if the plugin entry point - // is different than the standard one. - cache_manager(const std::string& path, - const std::string& name, - const std::string& symbol = default_symbol); - - // // Copy constructor - // cache_manager(cache_manager &other); - - // Move constructor - cache_manager(cache_manager&& old); - - ~cache_manager(); - - // Creates the instance of the cache_manager - // - // \return false if the cache_manager failed to be instantiated or if - // the cache_manager is not a valid cache manager, true otherwise - bool make_instance(); - - template - std::shared_ptr - get() { - static_assert(std::is_base_of::value, - "I must implement plugin_base"); - return this->get(); - } - - // Helper to access internal loaded cache_manager - // - // Gives access to the methods of the cache_manager using the operator - // -> (e.g.: cache_manager->get_name()); - cache_manager_iface* operator->(); - const cache_manager_iface* operator->() const; - - // helper function to check if a cache_manager is instantiated or not - friend bool operator==(std::nullptr_t nullp, const cache_manager& p); - - // helper function to check if a cache_manager is instantiated or not - friend bool operator==(const cache_manager& p, std::nullptr_t nullp); - - // helper function to check if a cache_manager is instantiated or not - friend bool operator!=(std::nullptr_t nullp, const cache_manager& p); - - // helper function to check if a cache_manager is instantiated or not - friend bool operator!=(const cache_manager& p, std::nullptr_t nullp); -}; -} -} diff --git a/cameradar_standalone/include/cameradar_task.h b/cameradar_standalone/include/cameradar_task.h deleted file mode 100644 index 6ca116d..0000000 --- a/cameradar_standalone/include/cameradar_task.h +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2016 Etix Labs -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -#include // std::string -#include // std::shared_ptr -#include // conf - -namespace etix { - -namespace cameradar { - -class cameradar_task { -public: - virtual bool run() const = 0; -}; -} -} diff --git a/cameradar_standalone/include/configuration.h b/cameradar_standalone/include/configuration.h deleted file mode 100644 index 1a66cd6..0000000 --- a/cameradar_standalone/include/configuration.h +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright 2016 Etix Labs -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -#include // Json::Value -#include // Json::Value -#include // _LOG_ -#include // parsing opt -#include // std::string -#include // std::pair - -namespace etix { - -namespace cameradar { - -static const std::string default_configuration_path = "conf/cameradar.conf.json"; - -static const std::string default_ports = "554,8554"; -static const std::string default_target = "localhost,168.0.0.0/24"; -static const std::string default_thumbnail_storage_path = "/tmp"; -static const std::string default_rtsp_url_file = "conf/url.json"; -static const std::string default_rtsp_ids_file = "conf/ids.json"; -static const std::string default_cache_manager_path = "../cache_managers/dumb_cache_manager"; -static const std::string default_cache_manager_name = "dumb"; - -struct configuration { - std::string thumbnail_storage_path; - std::string target; - std::string rtsp_url_file; - std::string rtsp_ids_file; - std::string ports; - std::string cache_manager_path; - std::string cache_manager_name; - std::vector paths; - std::vector usernames; - std::vector passwords; - - Json::Value raw_conf; - - configuration() = default; - configuration(const std::string& thumbnail_storage_path, - const std::string& target, - const std::string& rtsp_url_file, - const std::string& rtsp_ids_file, - const std::string& cache_manager_path, - const std::string& cache_manager_name, - const std::string& ports) - : thumbnail_storage_path(thumbnail_storage_path) - , target(target) - , rtsp_url_file(rtsp_url_file) - , rtsp_ids_file(rtsp_ids_file) - , ports(ports) - , cache_manager_path(cache_manager_path) - , cache_manager_name(cache_manager_name) {} - - static const std::string name_; - - bool load_ids(); - bool load_url(); - - Json::Value get_raw() const; -}; - -std::pair read_file(const std::string& path); -std::pair load(const std::pair& args); -} -} diff --git a/cameradar_standalone/include/describe.h b/cameradar_standalone/include/describe.h deleted file mode 100644 index c04a252..0000000 --- a/cameradar_standalone/include/describe.h +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2016 Etix Labs -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -#include // std::shared_ptr -#include // LOG -#include // cURL client for discovery -#include // b64 - -namespace etix { -namespace cameradar { -bool curl_describe(const std::string& path, bool logs); -} -} diff --git a/cameradar_standalone/include/dispatcher.h b/cameradar_standalone/include/dispatcher.h deleted file mode 100644 index af54667..0000000 --- a/cameradar_standalone/include/dispatcher.h +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright 2016 Etix Labs -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -#include // sig -#include // std::shared_ptr -#include // parsing opt -#include // LOG -#include // conf -#include // std::thread -#include // operator""ms -#include // sig - -// All the tasks managed by the dispatcher -#include -#include -#include -#include -#include -#include -#include - -namespace etix { -namespace cameradar { - -enum class task { - init, - preparation, - mapping, - parsing, - path_attack, - creds_attack, - thumb_generation, - print, - finished -}; - -class dispatcher { -private: - bool busy; - task current; - std::string nmap_output; - const configuration& conf; - std::shared_ptr cache; - const std::pair& opts; - std::list queue; - -public: - dispatcher() = delete; - dispatcher(const configuration& conf, - std::shared_ptr cache, - const std::pair& opts) - : busy(false) - , current(task::init) - , nmap_output("/tmp/scans/scan" + std::to_string(std::chrono::system_clock::to_time_t( - std::chrono::system_clock::now())) + - ".xml") - , conf(conf) - , cache(cache) - , opts(opts){}; - ~dispatcher() = default; - bool - doing_stuff() const { - return this->busy; - } - - void do_stuff(); - - void run(); -}; -} -} diff --git a/cameradar_standalone/include/encode.h b/cameradar_standalone/include/encode.h deleted file mode 100644 index 03ea1e4..0000000 --- a/cameradar_standalone/include/encode.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - base64.cpp and base64.h - Copyright (C) 2004-2008 René Nyffenegger - This source code is provided 'as-is', without any express or implied - warranty. In no event will the author be held liable for any damages - arising from the use of this software. - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - 1. The origin of this source code must not be misrepresented; you must not - claim that you wrote the original source code. If you use this source code - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original source code. - 3. This notice may not be removed or altered from any source distribution. - René Nyffenegger rene.nyffenegger@adp-gmbh.ch -*/ -#pragma once - -#include - -namespace etix { - -namespace tool { - -namespace encode { - -std::string encode64(const std::string& str_to_encode); - -std::string base64_encode(unsigned char const*, unsigned int len); -std::string base64_decode(std::string const& s); - -} // encode - -} // tool - -} // etix diff --git a/cameradar_standalone/include/fmt.h b/cameradar_standalone/include/fmt.h deleted file mode 100644 index 3847065..0000000 --- a/cameradar_standalone/include/fmt.h +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2016 Etix Labs -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -#include -#include -#include - -namespace etix { - -namespace tool { - -static std::mutex mutex; - -// Format a string with the given arguments -// same behavior as sprintf. -template -std::string -fmt(const std::string& base, Args... args) { - std::lock_guard guard(mutex); - static char buf[512]; - - std::sprintf(buf, base.c_str(), args...); - - return std::string(buf); -} - -} // tool - -} // etix diff --git a/cameradar_standalone/include/fs.h b/cameradar_standalone/include/fs.h deleted file mode 100644 index 265e36c..0000000 --- a/cameradar_standalone/include/fs.h +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2016 Etix Labs -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -#include -#include -#include -#include -#include - -namespace etix { - -namespace tool { - -namespace fs { - -enum class fs_error { is_dir, is_not_dir, dont_exist }; - -fs_error is_folder(const std::string& folder); -bool get_or_create_folder(const std::string& folder); -bool create_folder(const std::string& folder); -bool create_recursive_folder(const std::string& folder); -std::string home(); - -// this functions take a copy because we need to make some operations on the string -// for example, we need to apply std::string::pop_back -std::string get_file_folder(std::string full_file_path); - -bool copy(const std::string& src, const std::string& dst); - -} // fs - -} // tool - -} // etix diff --git a/cameradar_standalone/include/launch_command.h b/cameradar_standalone/include/launch_command.h deleted file mode 100644 index 2909440..0000000 --- a/cameradar_standalone/include/launch_command.h +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2016 Etix Labs -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -#include // std::string -#include // LOG -#include // system - -namespace etix { -namespace cameradar { -bool launch_command(const std::string& cmd); -} -} diff --git a/cameradar_standalone/include/logger.h b/cameradar_standalone/include/logger.h deleted file mode 100644 index ddfadbf..0000000 --- a/cameradar_standalone/include/logger.h +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright 2016 Etix Labs -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -#include "spdlog/spdlog.h" -#include -#include - -namespace etix { - -namespace tool { - -enum class loglevel { DEBUG = 1, INFO = 2, WARN = 4, ERR = 5, CRITICAL = 6 }; - -inline std::string -format_output(const std::string& from, const std::string& message) { - auto ss = std::stringstream{}; - - ss << "(" << from << "): "; - ss << message; - - return ss.str(); -} - -class logger { - std::string name; - std::shared_ptr console; - - logger(const std::string& plugin) - : name(plugin), console(spdlog::stdout_logger_mt("cameradar")) {} - -public: - static logger& - get_instance(const std::string& name = "") { - static logger self(name); - return self; - } - void - set_level(loglevel level) { - switch (level) { - case loglevel::DEBUG: this->console->set_level(spdlog::level::level_enum::debug); break; - - case loglevel::INFO: this->console->set_level(spdlog::level::level_enum::info); break; - - case loglevel::WARN: this->console->set_level(spdlog::level::level_enum::warn); break; - - case loglevel::ERR: this->console->set_level(spdlog::level::level_enum::err); break; - - case loglevel::CRITICAL: - this->console->set_level(spdlog::level::level_enum::critical); - break; - } - } - - static void - info(const std::string& message) { - etix::tool::logger::get_instance().console->info(message); - } - - static void - warn(const std::string& message) { - etix::tool::logger::get_instance().console->warn(message); - } - - static void - err(const std::string& message) { - etix::tool::logger::get_instance().console->error(message); - } - - static void - debug(const std::string& message) { - etix::tool::logger::get_instance().console->debug(message); - } -}; -} -} - -// Should be replaced to calls to spdlog::logger::getlogger(const std::string& -// name) -#define LOG_WARN_(message, from) \ - etix::tool::logger::get_instance().warn(etix::tool::format_output( \ - std::string(from) + "::" + __FUNCTION__ + ":" + std::to_string(__LINE__), message)) -#define LOG_ERR_(message, from) \ - etix::tool::logger::get_instance().err(etix::tool::format_output( \ - std::string(from) + "::" + __FUNCTION__ + ":" + std::to_string(__LINE__), message)) -#define LOG_DEBUG_(message, from) \ - etix::tool::logger::get_instance().debug(etix::tool::format_output( \ - std::string(from) + "::" + __FUNCTION__ + ":" + std::to_string(__LINE__), message)) -#define LOG_INFO_(message, from) \ - etix::tool::logger::get_instance().info(etix::tool::format_output( \ - std::string(from) + "::" + __FUNCTION__ + ":" + std::to_string(__LINE__), message)) diff --git a/cameradar_standalone/include/opt_parse.h b/cameradar_standalone/include/opt_parse.h deleted file mode 100644 index 38edf48..0000000 --- a/cameradar_standalone/include/opt_parse.h +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright 2016 Etix Labs -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -#include // for string -#include // for unordered_map -#include // for pair -#include // for vector - -namespace etix { - -namespace tool { - -class opt_parse { -private: - struct opt_param { - bool required; - bool need_arg; - std::string name; - std::string desc; - std::string argument; - bool is_passed = false; - - opt_param(bool required, bool need_arg, std::string name, std::string desc) - : required(required), need_arg(need_arg), name(name), desc(desc) {} - }; - - std::unordered_map params; - int argc; - char** argv; - int params_cnt = 0; - -public: - class iterator { - private: - std::vector> args; - unsigned int opt_pos = 0; - - public: - iterator(std::vector> args, unsigned int opt_pos) - : args(args), opt_pos(opt_pos) {} - iterator operator++() { - this->opt_pos += 1; - return *this; - } - std::pair& operator*() { return this->args.at(this->opt_pos); } - bool - operator==(const iterator& rhs) const { - return this->opt_pos == rhs.opt_pos; - } - bool - operator!=(const iterator& rhs) const { - return this->opt_pos != rhs.opt_pos; - } - }; - - opt_parse() = delete; - - opt_parse(int argc, char* argv[]); - - ~opt_parse(); - - void required(const std::string& name, const std::string& desc = "", bool need_arg = true); - - void optional(const std::string& name, const std::string& desc = "", bool need_arg = true); - - bool execute(); - - iterator begin() const; - - iterator end() const; - - void print_usage() const; - - void print_help() const; - - bool has_error() const; - - bool exist(const std::string& opt) const; - - std::string operator[](const std::string& opt) const; -}; - -} // tool - -} // etix diff --git a/cameradar_standalone/include/rtsp_path.h b/cameradar_standalone/include/rtsp_path.h deleted file mode 100644 index 2a2208a..0000000 --- a/cameradar_standalone/include/rtsp_path.h +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2016 Etix Labs -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -#include // for string -#include // for stream_model - -namespace etix { - -namespace cameradar { - -const std::string make_path(const stream_model& model); -} -} diff --git a/cameradar_standalone/include/signal_handler.h b/cameradar_standalone/include/signal_handler.h deleted file mode 100644 index 9813182..0000000 --- a/cameradar_standalone/include/signal_handler.h +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2016 Etix Labs -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -#include // assert -#include // sigint -#include // stc::cout - -// To avoid an unused warning for the asserted in handle_signal -#define _unused(x) ((void)(x)) - -namespace etix { - -namespace cameradar { - -enum class stop_priority { running, stop, force_stop }; - -class event_handler { -public: - event_handler(void) : ss(stop_priority::running) {} - - virtual int - handle_signal(int signum) { - assert(signum == SIGINT); - _unused(signum); - std::cout << "\b\b\b\033[K"; - if (this->ss == stop_priority::running) - this->ss = stop_priority::stop; - else - this->ss = stop_priority::force_stop; - return 0; - } - - etix::cameradar::stop_priority - should_stop(void) const { - return this->ss; - } - -private: - stop_priority ss; -}; - -class signal_handler { -private: - signal_handler(void); - signal_handler(const signal_handler&); - signal_handler& operator=(const signal_handler&); - - static void call_handler(int signum); - - static event_handler handler; - -public: - static signal_handler& instance(void); - etix::cameradar::stop_priority should_stop(void) const; -}; -} -} diff --git a/cameradar_standalone/include/spdlog/async_logger.h b/cameradar_standalone/include/spdlog/async_logger.h deleted file mode 100644 index 3e45c0f..0000000 --- a/cameradar_standalone/include/spdlog/async_logger.h +++ /dev/null @@ -1,71 +0,0 @@ -// -// Copyright(c) 2015 Gabi Melman. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) -// - -#pragma once - -// Very fast asynchronous logger (millions of logs per second on an average desktop) -// Uses pre allocated lockfree queue for maximum throughput even under large number of threads. -// Creates a single back thread to pop messages from the queue and log them. -// -// Upon each log write the logger: -// 1. Checks if its log level is enough to log the message -// 2. Push a new copy of the message to a queue (or block the caller until space is available in -// the queue) -// 3. will throw spdlog_ex upon log exceptions -// Upong destruction, logs all remaining messages in the queue before destructing.. - -#include -#include -#include "common.h" -#include "logger.h" -#include "spdlog.h" - -namespace spdlog { - -namespace details { -class async_log_helper; -} - -class async_logger : public logger { -public: - template - async_logger( - const std::string& name, - const It& begin, - const It& end, - size_t queue_size, - const async_overflow_policy overflow_policy = async_overflow_policy::block_retry, - const std::function& worker_warmup_cb = nullptr, - const std::chrono::milliseconds& flush_interval_ms = std::chrono::milliseconds::zero()); - - async_logger( - const std::string& logger_name, - sinks_init_list sinks, - size_t queue_size, - const async_overflow_policy overflow_policy = async_overflow_policy::block_retry, - const std::function& worker_warmup_cb = nullptr, - const std::chrono::milliseconds& flush_interval_ms = std::chrono::milliseconds::zero()); - - async_logger( - const std::string& logger_name, - sink_ptr single_sink, - size_t queue_size, - const async_overflow_policy overflow_policy = async_overflow_policy::block_retry, - const std::function& worker_warmup_cb = nullptr, - const std::chrono::milliseconds& flush_interval_ms = std::chrono::milliseconds::zero()); - - void flush() override; - -protected: - void _log_msg(details::log_msg& msg) override; - void _set_formatter(spdlog::formatter_ptr msg_formatter) override; - void _set_pattern(const std::string& pattern) override; - -private: - std::unique_ptr _async_log_helper; -}; -} - -#include "./details/async_logger_impl.h" diff --git a/cameradar_standalone/include/spdlog/common.h b/cameradar_standalone/include/spdlog/common.h deleted file mode 100644 index 0f25667..0000000 --- a/cameradar_standalone/include/spdlog/common.h +++ /dev/null @@ -1,88 +0,0 @@ -// -// Copyright(c) 2015 Gabi Melman. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) -// - -#pragma once - -#include -#include -#include -#include - -// visual studio does not support noexcept yet -#ifndef _MSC_VER -#define SPDLOG_NOEXCEPT noexcept -#else -#define SPDLOG_NOEXCEPT throw() -#endif - -namespace spdlog { - -class formatter; - -namespace sinks { -class sink; -} - -// Common types across the lib -using log_clock = std::chrono::system_clock; -using sink_ptr = std::shared_ptr; -using sinks_init_list = std::initializer_list; -using formatter_ptr = std::shared_ptr; - -// Log level enum -namespace level { -typedef enum { - trace = 0, - debug = 1, - info = 2, - notice = 3, - warn = 4, - err = 5, - critical = 6, - alert = 7, - emerg = 8, - off = 9 -} level_enum; - -static const char* level_names[]{ "trace", "debug", "info", "notice", "warning", - "error", "critical", "alert", "emerg", "off" }; - -static const char* short_level_names[]{ "T", "D", "I", "N", "W", "E", "C", "A", "M", "O" }; - -inline const char* -to_str(spdlog::level::level_enum l) { - return level_names[l]; -} - -inline const char* -to_short_str(spdlog::level::level_enum l) { - return short_level_names[l]; -} -} // level - -// -// Async overflow policy - block by default. -// -enum class async_overflow_policy { - block_retry, // Block / yield / sleep until message can be enqueued - discard_log_msg // Discard the message it enqueue fails -}; - -// -// Log exception -// -class spdlog_ex : public std::exception { -public: - explicit spdlog_ex(const std::string& msg) : _msg(msg) {} - const char* - what() const SPDLOG_NOEXCEPT override { - return _msg.c_str(); - } - -private: - std::string _msg; -}; - -} // spdlog diff --git a/cameradar_standalone/include/spdlog/details/async_log_helper.h b/cameradar_standalone/include/spdlog/details/async_log_helper.h deleted file mode 100644 index 3501039..0000000 --- a/cameradar_standalone/include/spdlog/details/async_log_helper.h +++ /dev/null @@ -1,313 +0,0 @@ -// -// Copyright(c) 2015 Gabi Melman. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) -// - -// async log helper : -// Process logs asynchronously using a back thread. -// -// If the internal queue of log messages reaches its max size, -// then the client call will block until there is more room. -// -// If the back thread throws during logging, a spdlog::spdlog_ex exception -// will be thrown in client's thread when tries to log the next message - -#pragma once - -#include -#include -#include - -#include "../common.h" -#include "../sinks/sink.h" -#include "./mpmc_bounded_q.h" -#include "./log_msg.h" -#include "./format.h" -#include "./os.h" - -namespace spdlog { -namespace details { - -class async_log_helper { - // Async msg to move to/from the queue - // Movable only. should never be copied - enum class async_msg_type { log, flush, terminate }; - struct async_msg { - std::string logger_name; - level::level_enum level; - log_clock::time_point time; - size_t thread_id; - std::string txt; - async_msg_type msg_type; - - async_msg() = default; - ~async_msg() = default; - - async_msg(async_msg&& other) SPDLOG_NOEXCEPT : logger_name(std::move(other.logger_name)), - level(std::move(other.level)), - time(std::move(other.time)), - txt(std::move(other.txt)), - msg_type(std::move(other.msg_type)) {} - - async_msg(async_msg_type m_type) : msg_type(m_type){}; - - async_msg& operator=(async_msg&& other) SPDLOG_NOEXCEPT { - logger_name = std::move(other.logger_name); - level = other.level; - time = std::move(other.time); - thread_id = other.thread_id; - txt = std::move(other.txt); - msg_type = other.msg_type; - return *this; - } - - // never copy or assign. should only be moved.. - async_msg(const async_msg&) = delete; - async_msg& operator=(async_msg& other) = delete; - - // construct from log_msg - async_msg(const details::log_msg& m) - : logger_name(m.logger_name) - , level(m.level) - , time(m.time) - , thread_id(m.thread_id) - , txt(m.raw.data(), m.raw.size()) - , msg_type(async_msg_type::log) {} - - // copy into log_msg - void - fill_log_msg(log_msg& msg) { - msg.clear(); - msg.logger_name = logger_name; - msg.level = level; - msg.time = time; - msg.thread_id = thread_id; - msg.raw << txt; - } - }; - -public: - using item_type = async_msg; - using q_type = details::mpmc_bounded_queue; - - using clock = std::chrono::steady_clock; - - async_log_helper( - formatter_ptr formatter, - const std::vector& sinks, - size_t queue_size, - const async_overflow_policy overflow_policy = async_overflow_policy::block_retry, - const std::function& worker_warmup_cb = nullptr, - const std::chrono::milliseconds& flush_interval_ms = std::chrono::milliseconds::zero()); - - void log(const details::log_msg& msg); - - // stop logging and join the back thread - ~async_log_helper(); - - void set_formatter(formatter_ptr); - - void flush(); - -private: - formatter_ptr _formatter; - std::vector> _sinks; - - // queue of messages to log - q_type _q; - - bool _flush_requested; - - bool _terminate_requested; - - // last exception thrown from the worker thread - std::shared_ptr _last_workerthread_ex; - - // overflow policy - const async_overflow_policy _overflow_policy; - - // worker thread warmup callback - one can set thread priority, affinity, etc - const std::function _worker_warmup_cb; - - // auto periodic sink flush parameter - const std::chrono::milliseconds _flush_interval_ms; - - // worker thread - std::thread _worker_thread; - - void push_msg(async_msg&& new_msg); - // throw last worker thread exception or if worker thread is not active - - void throw_if_bad_worker(); - - // worker thread main loop - void worker_loop(); - - // pop next message from the queue and process it. will set the last_pop to the pop time - // return false if termination of the queue is required - bool process_next_msg(log_clock::time_point& last_pop, log_clock::time_point& last_flush); - - void handle_flush_interval(log_clock::time_point& now, log_clock::time_point& last_flush); - - // sleep,yield or return immediatly using the time passed since last message as a hint - static void sleep_or_yield(const spdlog::log_clock::time_point& now, - const log_clock::time_point& last_op_time); -}; -} -} - -/////////////////////////////////////////////////////////////////////////////// -// async_sink class implementation -/////////////////////////////////////////////////////////////////////////////// -inline spdlog::details::async_log_helper::async_log_helper( - formatter_ptr formatter, - const std::vector& sinks, - size_t queue_size, - const async_overflow_policy overflow_policy, - const std::function& worker_warmup_cb, - const std::chrono::milliseconds& flush_interval_ms) -: _formatter(formatter) -, _sinks(sinks) -, _q(queue_size) -, _flush_requested(false) -, _terminate_requested(false) -, _overflow_policy(overflow_policy) -, _worker_warmup_cb(worker_warmup_cb) -, _flush_interval_ms(flush_interval_ms) -, _worker_thread(&async_log_helper::worker_loop, this) {} - -// Send to the worker thread termination message(level=off) -// and wait for it to finish gracefully -inline spdlog::details::async_log_helper::~async_log_helper() { - try { - push_msg(async_msg(async_msg_type::terminate)); - _worker_thread.join(); - } catch (...) // don't crash in destructor - {} -} - -// Try to push and block until succeeded -inline void -spdlog::details::async_log_helper::log(const details::log_msg& msg) { - push_msg(async_msg(msg)); -} - -// Try to push and block until succeeded -inline void -spdlog::details::async_log_helper::push_msg(details::async_log_helper::async_msg&& new_msg) { - throw_if_bad_worker(); - if (!_q.enqueue(std::move(new_msg)) && - _overflow_policy != async_overflow_policy::discard_log_msg) { - auto last_op_time = details::os::now(); - auto now = last_op_time; - do { - now = details::os::now(); - sleep_or_yield(now, last_op_time); - } while (!_q.enqueue(std::move(new_msg))); - } -} - -inline void -spdlog::details::async_log_helper::flush() { - push_msg(async_msg(async_msg_type::flush)); -} - -inline void -spdlog::details::async_log_helper::worker_loop() { - try { - if (_worker_warmup_cb) _worker_warmup_cb(); - auto last_pop = details::os::now(); - auto last_flush = last_pop; - while (process_next_msg(last_pop, last_flush)) - ; - } catch (const std::exception& ex) { - _last_workerthread_ex = std::make_shared( - std::string("async_logger worker thread exception: ") + ex.what()); - } catch (...) { - _last_workerthread_ex = std::make_shared("async_logger worker thread exception"); - } -} - -// process next message in the queue -// return true if this thread should still be active (no msg with level::off was received) -inline bool -spdlog::details::async_log_helper::process_next_msg(log_clock::time_point& last_pop, - log_clock::time_point& last_flush) { - async_msg incoming_async_msg; - log_msg incoming_log_msg; - - if (_q.dequeue(incoming_async_msg)) { - last_pop = details::os::now(); - switch (incoming_async_msg.msg_type) { - case async_msg_type::flush: _flush_requested = true; break; - - case async_msg_type::terminate: - _flush_requested = true; - _terminate_requested = true; - break; - - default: - incoming_async_msg.fill_log_msg(incoming_log_msg); - _formatter->format(incoming_log_msg); - for (auto& s : _sinks) s->log(incoming_log_msg); - } - return true; - } - - // Handle empty queue.. - // This is the only place where the queue can terminate or flush to avoid losing messages - // already in the queue - else { - auto now = details::os::now(); - handle_flush_interval(now, last_flush); - sleep_or_yield(now, last_pop); - return !_terminate_requested; - } -} - -inline void -spdlog::details::async_log_helper::handle_flush_interval(log_clock::time_point& now, - log_clock::time_point& last_flush) { - auto should_flush = - _flush_requested || (_flush_interval_ms != std::chrono::milliseconds::zero() && - now - last_flush >= _flush_interval_ms); - if (should_flush) { - for (auto& s : _sinks) s->flush(); - now = last_flush = details::os::now(); - _flush_requested = false; - } -} -inline void -spdlog::details::async_log_helper::set_formatter(formatter_ptr msg_formatter) { - _formatter = msg_formatter; -} - -// sleep,yield or return immediatly using the time passed since last message as a hint -inline void -spdlog::details::async_log_helper::sleep_or_yield( - const spdlog::log_clock::time_point& now, const spdlog::log_clock::time_point& last_op_time) { - using std::chrono::milliseconds; - using namespace std::this_thread; - - auto time_since_op = now - last_op_time; - - // spin upto 1 ms - if (time_since_op <= milliseconds(1)) return; - - // yield upto 10ms - if (time_since_op <= milliseconds(10)) return yield(); - - // sleep for half of duration since last op - if (time_since_op <= milliseconds(100)) return sleep_for(time_since_op / 2); - - return sleep_for(milliseconds(100)); -} - -// throw if the worker thread threw an exception or not active -inline void -spdlog::details::async_log_helper::throw_if_bad_worker() { - if (_last_workerthread_ex) { - auto ex = std::move(_last_workerthread_ex); - throw * ex; - } -} diff --git a/cameradar_standalone/include/spdlog/details/async_logger_impl.h b/cameradar_standalone/include/spdlog/details/async_logger_impl.h deleted file mode 100644 index 368eaaa..0000000 --- a/cameradar_standalone/include/spdlog/details/async_logger_impl.h +++ /dev/null @@ -1,72 +0,0 @@ -// -// Copyright(c) 2015 Gabi Melman. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) -// - -#pragma once - -// Async Logger implementation -// Use an async_sink (queue per logger) to perform the logging in a worker thread - -#include "./async_log_helper.h" - -template -inline spdlog::async_logger::async_logger(const std::string& logger_name, - const It& begin, - const It& end, - size_t queue_size, - const async_overflow_policy overflow_policy, - const std::function& worker_warmup_cb, - const std::chrono::milliseconds& flush_interval_ms) -: logger(logger_name, begin, end) -, _async_log_helper(new details::async_log_helper( - _formatter, _sinks, queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms)) {} - -inline spdlog::async_logger::async_logger(const std::string& logger_name, - sinks_init_list sinks, - size_t queue_size, - const async_overflow_policy overflow_policy, - const std::function& worker_warmup_cb, - const std::chrono::milliseconds& flush_interval_ms) -: async_logger(logger_name, - sinks.begin(), - sinks.end(), - queue_size, - overflow_policy, - worker_warmup_cb, - flush_interval_ms) {} - -inline spdlog::async_logger::async_logger(const std::string& logger_name, - sink_ptr single_sink, - size_t queue_size, - const async_overflow_policy overflow_policy, - const std::function& worker_warmup_cb, - const std::chrono::milliseconds& flush_interval_ms) -: async_logger(logger_name, - { single_sink }, - queue_size, - overflow_policy, - worker_warmup_cb, - flush_interval_ms) {} - -inline void -spdlog::async_logger::flush() { - _async_log_helper->flush(); -} - -inline void -spdlog::async_logger::_set_formatter(spdlog::formatter_ptr msg_formatter) { - _formatter = msg_formatter; - _async_log_helper->set_formatter(_formatter); -} - -inline void -spdlog::async_logger::_set_pattern(const std::string& pattern) { - _formatter = std::make_shared(pattern); - _async_log_helper->set_formatter(_formatter); -} - -inline void -spdlog::async_logger::_log_msg(details::log_msg& msg) { - _async_log_helper->log(msg); -} diff --git a/cameradar_standalone/include/spdlog/details/file_helper.h b/cameradar_standalone/include/spdlog/details/file_helper.h deleted file mode 100644 index 5e1fe43..0000000 --- a/cameradar_standalone/include/spdlog/details/file_helper.h +++ /dev/null @@ -1,117 +0,0 @@ -// -// Copyright(c) 2015 Gabi Melman. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) -// - -#pragma once - -// Helper class for file sink -// When failing to open a file, retry several times(5) with small delay between the tries(10 ms) -// Can be set to auto flush on every line -// Throw spdlog_ex exception on errors - -#include -#include -#include -#include "os.h" -#include "log_msg.h" - -namespace spdlog { -namespace details { - -class file_helper { -public: - const int open_tries = 5; - const int open_interval = 10; - - explicit file_helper(bool force_flush) : _fd(nullptr), _force_flush(force_flush) {} - - file_helper(const file_helper&) = delete; - file_helper& operator=(const file_helper&) = delete; - - ~file_helper() { close(); } - - void - open(const std::string& fname, bool truncate = false) { - close(); - const char* mode = truncate ? "wb" : "ab"; - _filename = fname; - for (int tries = 0; tries < open_tries; ++tries) { - if (!os::fopen_s(&_fd, fname, mode)) return; - - std::this_thread::sleep_for(std::chrono::milliseconds(open_interval)); - } - - throw spdlog_ex("Failed opening file " + fname + " for writing"); - } - - void - reopen(bool truncate) { - if (_filename.empty()) throw spdlog_ex("Failed re opening file - was not opened before"); - open(_filename, truncate); - } - - void - flush() { - std::fflush(_fd); - } - - void - close() { - if (_fd) { - std::fclose(_fd); - _fd = nullptr; - } - } - - void - write_string(const std::string& msg) { - if (std::fwrite(msg.c_str(), 1, msg.size(), _fd) != msg.size()) - throw spdlog_ex("Failed writing to file " + _filename); - - if (_force_flush) std::fflush(_fd); - } - - void - write(const log_msg& msg) { - size_t msg_size = msg.formatted.size(); - auto data = msg.formatted.data(); - if (std::fwrite(data, 1, msg_size, _fd) != msg_size) - throw spdlog_ex("Failed writing to file " + _filename); - - if (_force_flush) std::fflush(_fd); - } - - long - size() { - if (!_fd) throw spdlog_ex("Cannot use size() on closed file " + _filename); - - auto pos = ftell(_fd); - if (fseek(_fd, 0, SEEK_END) != 0) throw spdlog_ex("fseek failed on file " + _filename); - - auto file_size = ftell(_fd); - - if (fseek(_fd, pos, SEEK_SET) != 0) throw spdlog_ex("fseek failed on file " + _filename); - - if (file_size == -1) throw spdlog_ex("ftell failed on file " + _filename); - - return file_size; - } - - const std::string& - filename() const { - return _filename; - } - - static bool - file_exists(const std::string& name) { - return os::file_exists(name); - } - -private: - FILE* _fd; - std::string _filename; - bool _force_flush; -}; -} -} diff --git a/cameradar_standalone/include/spdlog/details/format.cc b/cameradar_standalone/include/spdlog/details/format.cc deleted file mode 100644 index e396688..0000000 --- a/cameradar_standalone/include/spdlog/details/format.cc +++ /dev/null @@ -1,934 +0,0 @@ -/* -Formatting library for C++ - -Copyright (c) 2012 - 2015, Victor Zverovich -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this -list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright notice, -this list of conditions and the following disclaimer in the documentation -and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#include "format.h" - -#include - -#include -#include -#include -#include -#include -#include // for std::ptrdiff_t - -#if defined(_WIN32) && defined(__MINGW32__) -#include -#endif - -#if FMT_USE_WINDOWS_H -#if defined(NOMINMAX) || defined(FMT_WIN_MINMAX) -#include -#else -#define NOMINMAX -#include -#undef NOMINMAX -#endif -#endif - -using fmt::internal::Arg; - -#if FMT_EXCEPTIONS -#define FMT_TRY try -#define FMT_CATCH(x) catch (x) -#else -#define FMT_TRY if (true) -#define FMT_CATCH(x) if (false) -#endif - -#ifdef FMT_HEADER_ONLY -#define FMT_FUNC inline -#else -#define FMT_FUNC -#endif - -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable : 4127) // conditional expression is constant -#pragma warning(disable : 4702) // unreachable code -// Disable deprecation warning for strerror. The latter is not called but -// MSVC fails to detect it. -#pragma warning(disable : 4996) -#endif - -// Dummy implementations of strerror_r and strerror_s called if corresponding -// system functions are not available. -static inline fmt::internal::Null<> -strerror_r(int, char*, ...) { - return fmt::internal::Null<>(); -} -static inline fmt::internal::Null<> -strerror_s(char*, std::size_t, ...) { - return fmt::internal::Null<>(); -} - -namespace fmt { -namespace { - -#ifndef _MSC_VER -#define FMT_SNPRINTF snprintf -#else // _MSC_VER -inline int -fmt_snprintf(char* buffer, size_t size, const char* format, ...) { - va_list args; - va_start(args, format); - int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args); - va_end(args); - return result; -} -#define FMT_SNPRINTF fmt_snprintf -#endif // _MSC_VER - -#if defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT) -#define FMT_SWPRINTF snwprintf -#else -#define FMT_SWPRINTF swprintf -#endif // defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT) - -// Checks if a value fits in int - used to avoid warnings about comparing -// signed and unsigned integers. -template -struct IntChecker { - template - static bool - fits_in_int(T value) { - unsigned max = INT_MAX; - return value <= max; - } - static bool - fits_in_int(bool) { - return true; - } -}; - -template <> -struct IntChecker { - template - static bool - fits_in_int(T value) { - return value >= INT_MIN && value <= INT_MAX; - } - static bool - fits_in_int(int) { - return true; - } -}; - -const char RESET_COLOR[] = "\x1b[0m"; - -typedef void (*FormatFunc)(fmt::Writer&, int, fmt::StringRef); - -// Portable thread-safe version of strerror. -// Sets buffer to point to a string describing the error code. -// This can be either a pointer to a string stored in buffer, -// or a pointer to some static immutable string. -// Returns one of the following values: -// 0 - success -// ERANGE - buffer is not large enough to store the error message -// other - failure -// Buffer should be at least of size 1. -int -safe_strerror(int error_code, char*& buffer, std::size_t buffer_size) FMT_NOEXCEPT { - FMT_ASSERT(buffer != 0 && buffer_size != 0, "invalid buffer"); - - class StrError { - private: - int error_code_; - char*& buffer_; - std::size_t buffer_size_; - - // A noop assignment operator to avoid bogus warnings. - void operator=(const StrError&) {} - - // Handle the result of XSI-compliant version of strerror_r. - int - handle(int result) { - // glibc versions before 2.13 return result in errno. - return result == -1 ? errno : result; - } - - // Handle the result of GNU-specific version of strerror_r. - int - handle(char* message) { - // If the buffer is full then the message is probably truncated. - if (message == buffer_ && strlen(buffer_) == buffer_size_ - 1) return ERANGE; - buffer_ = message; - return 0; - } - - // Handle the case when strerror_r is not available. - int handle(fmt::internal::Null<>) { - return fallback(strerror_s(buffer_, buffer_size_, error_code_)); - } - - // Fallback to strerror_s when strerror_r is not available. - int - fallback(int result) { - // If the buffer is full then the message is probably truncated. - return result == 0 && strlen(buffer_) == buffer_size_ - 1 ? ERANGE : result; - } - - // Fallback to strerror if strerror_r and strerror_s are not available. - int fallback(fmt::internal::Null<>) { - errno = 0; - buffer_ = strerror(error_code_); - return errno; - } - - public: - StrError(int err_code, char*& buf, std::size_t buf_size) - : error_code_(err_code), buffer_(buf), buffer_size_(buf_size) {} - - int - run() { - strerror_r(0, 0, ""); // Suppress a warning about unused strerror_r. - return handle(strerror_r(error_code_, buffer_, buffer_size_)); - } - }; - return StrError(error_code, buffer, buffer_size).run(); -} - -void -format_error_code(fmt::Writer& out, int error_code, fmt::StringRef message) FMT_NOEXCEPT { - // Report error code making sure that the output fits into - // INLINE_BUFFER_SIZE to avoid dynamic memory allocation and potential - // bad_alloc. - out.clear(); - static const char SEP[] = ": "; - static const char ERROR_STR[] = "error "; - fmt::internal::IntTraits::MainType ec_value = error_code; - // Subtract 2 to account for terminating null characters in SEP and ERROR_STR. - std::size_t error_code_size = sizeof(SEP) + sizeof(ERROR_STR) - 2; - error_code_size += fmt::internal::count_digits(ec_value); - if (message.size() <= fmt::internal::INLINE_BUFFER_SIZE - error_code_size) - out << message << SEP; - out << ERROR_STR << error_code; - assert(out.size() <= fmt::internal::INLINE_BUFFER_SIZE); -} - -void -report_error(FormatFunc func, int error_code, fmt::StringRef message) FMT_NOEXCEPT { - fmt::MemoryWriter full_message; - func(full_message, error_code, message); - // Use Writer::data instead of Writer::c_str to avoid potential memory - // allocation. - std::fwrite(full_message.data(), full_message.size(), 1, stderr); - std::fputc('\n', stderr); -} - -// IsZeroInt::visit(arg) returns true iff arg is a zero integer. -class IsZeroInt : public fmt::internal::ArgVisitor { -public: - template - bool - visit_any_int(T value) { - return value == 0; - } -}; - -// Checks if an argument is a valid printf width specifier and sets -// left alignment if it is negative. -class WidthHandler : public fmt::internal::ArgVisitor { -private: - fmt::FormatSpec& spec_; - - FMT_DISALLOW_COPY_AND_ASSIGN(WidthHandler); - -public: - explicit WidthHandler(fmt::FormatSpec& spec) : spec_(spec) {} - - void - report_unhandled_arg() { - FMT_THROW(fmt::FormatError("width is not integer")); - } - - template - unsigned - visit_any_int(T value) { - typedef typename fmt::internal::IntTraits::MainType UnsignedType; - UnsignedType width = value; - if (fmt::internal::is_negative(value)) { - spec_.align_ = fmt::ALIGN_LEFT; - width = 0 - width; - } - if (width > INT_MAX) FMT_THROW(fmt::FormatError("number is too big")); - return static_cast(width); - } -}; - -class PrecisionHandler : public fmt::internal::ArgVisitor { -public: - void - report_unhandled_arg() { - FMT_THROW(fmt::FormatError("precision is not integer")); - } - - template - int - visit_any_int(T value) { - if (!IntChecker::is_signed>::fits_in_int(value)) - FMT_THROW(fmt::FormatError("number is too big")); - return static_cast(value); - } -}; - -// Converts an integer argument to an integral type T for printf. -template -class ArgConverter : public fmt::internal::ArgVisitor, void> { -private: - fmt::internal::Arg& arg_; - wchar_t type_; - - FMT_DISALLOW_COPY_AND_ASSIGN(ArgConverter); - -public: - ArgConverter(fmt::internal::Arg& arg, wchar_t type) : arg_(arg), type_(type) {} - - void - visit_bool(bool value) { - if (type_ != 's') visit_any_int(value); - } - - template - void - visit_any_int(U value) { - bool is_signed = type_ == 'd' || type_ == 'i'; - using fmt::internal::Arg; - if (sizeof(T) <= sizeof(int)) { - // Extra casts are used to silence warnings. - if (is_signed) { - arg_.type = Arg::INT; - arg_.int_value = static_cast(static_cast(value)); - } else { - arg_.type = Arg::UINT; - arg_.uint_value = static_cast( - static_cast::Type>(value)); - } - } else { - if (is_signed) { - arg_.type = Arg::LONG_LONG; - arg_.long_long_value = - static_cast::Type>(value); - } else { - arg_.type = Arg::ULONG_LONG; - arg_.ulong_long_value = - static_cast::Type>(value); - } - } - } -}; - -// Converts an integer argument to char for printf. -class CharConverter : public fmt::internal::ArgVisitor { -private: - fmt::internal::Arg& arg_; - - FMT_DISALLOW_COPY_AND_ASSIGN(CharConverter); - -public: - explicit CharConverter(fmt::internal::Arg& arg) : arg_(arg) {} - - template - void - visit_any_int(T value) { - arg_.type = Arg::CHAR; - arg_.int_value = static_cast(value); - } -}; -} // namespace - -namespace internal { - -template -class PrintfArgFormatter : public ArgFormatterBase, Char> { - void - write_null_pointer() { - this->spec().type_ = 0; - this->write("(nil)"); - } - - typedef ArgFormatterBase, Char> Base; - -public: - PrintfArgFormatter(BasicWriter& w, FormatSpec& s) - : ArgFormatterBase, Char>(w, s) {} - - void - visit_bool(bool value) { - FormatSpec& fmt_spec = this->spec(); - if (fmt_spec.type_ != 's') return this->visit_any_int(value); - fmt_spec.type_ = 0; - this->write(value); - } - - void - visit_char(int value) { - const FormatSpec& fmt_spec = this->spec(); - BasicWriter& w = this->writer(); - if (fmt_spec.type_ && fmt_spec.type_ != 'c') w.write_int(value, fmt_spec); - typedef typename BasicWriter::CharPtr CharPtr; - CharPtr out = CharPtr(); - if (fmt_spec.width_ > 1) { - Char fill = ' '; - out = w.grow_buffer(fmt_spec.width_); - if (fmt_spec.align_ != ALIGN_LEFT) { - std::fill_n(out, fmt_spec.width_ - 1, fill); - out += fmt_spec.width_ - 1; - } else { - std::fill_n(out + 1, fmt_spec.width_ - 1, fill); - } - } else { - out = w.grow_buffer(1); - } - *out = static_cast(value); - } - - void - visit_cstring(const char* value) { - if (value) - Base::visit_cstring(value); - else if (this->spec().type_ == 'p') - write_null_pointer(); - else - this->write("(null)"); - } - - void - visit_pointer(const void* value) { - if (value) return Base::visit_pointer(value); - this->spec().type_ = 0; - write_null_pointer(); - } - - void - visit_custom(Arg::CustomValue c) { - BasicFormatter formatter(ArgList(), this->writer()); - const Char format_str[] = { '}', 0 }; - const Char* format = format_str; - c.format(&formatter, c.value, &format); - } -}; -} // namespace internal -} // namespace fmt - -FMT_FUNC void -fmt::SystemError::init(int err_code, CStringRef format_str, ArgList args) { - error_code_ = err_code; - MemoryWriter w; - internal::format_system_error(w, err_code, format(format_str, args)); - std::runtime_error& base = *this; - base = std::runtime_error(w.str()); -} - -template -int -fmt::internal::CharTraits::format_float( - char* buffer, std::size_t size, const char* format, unsigned width, int precision, T value) { - if (width == 0) { - return precision < 0 ? FMT_SNPRINTF(buffer, size, format, value) - : FMT_SNPRINTF(buffer, size, format, precision, value); - } - return precision < 0 ? FMT_SNPRINTF(buffer, size, format, width, value) - : FMT_SNPRINTF(buffer, size, format, width, precision, value); -} - -template -int -fmt::internal::CharTraits::format_float(wchar_t* buffer, - std::size_t size, - const wchar_t* format, - unsigned width, - int precision, - T value) { - if (width == 0) { - return precision < 0 ? FMT_SWPRINTF(buffer, size, format, value) - : FMT_SWPRINTF(buffer, size, format, precision, value); - } - return precision < 0 ? FMT_SWPRINTF(buffer, size, format, width, value) - : FMT_SWPRINTF(buffer, size, format, width, precision, value); -} - -template -const char fmt::internal::BasicData::DIGITS[] = - "0001020304050607080910111213141516171819" - "2021222324252627282930313233343536373839" - "4041424344454647484950515253545556575859" - "6061626364656667686970717273747576777879" - "8081828384858687888990919293949596979899"; - -#define FMT_POWERS_OF_10(factor) \ - factor * 10, factor * 100, factor * 1000, factor * 10000, factor * 100000, factor * 1000000, \ - factor * 10000000, factor * 100000000, factor * 1000000000 - -template -const uint32_t fmt::internal::BasicData::POWERS_OF_10_32[] = { 0, FMT_POWERS_OF_10(1) }; - -template -const uint64_t fmt::internal::BasicData::POWERS_OF_10_64[] = { - 0, - FMT_POWERS_OF_10(1), - FMT_POWERS_OF_10(fmt::ULongLong(1000000000)), - // Multiply several constants instead of using a single long long constant - // to avoid warnings about C++98 not supporting long long. - fmt::ULongLong(1000000000) * fmt::ULongLong(1000000000) * 10 -}; - -FMT_FUNC void -fmt::internal::report_unknown_type(char code, const char* type) { - (void)type; - if (std::isprint(static_cast(code))) { - FMT_THROW(fmt::FormatError(fmt::format("unknown format code '{}' for {}", code, type))); - } - FMT_THROW(fmt::FormatError( - fmt::format("unknown format code '\\x{:02x}' for {}", static_cast(code), type))); -} - -#if FMT_USE_WINDOWS_H - -FMT_FUNC -fmt::internal::UTF8ToUTF16::UTF8ToUTF16(fmt::StringRef s) { - static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16"; - if (s.size() > INT_MAX) FMT_THROW(WindowsError(ERROR_INVALID_PARAMETER, ERROR_MSG)); - int s_size = static_cast(s.size()); - int length = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, 0, 0); - if (length == 0) FMT_THROW(WindowsError(GetLastError(), ERROR_MSG)); - buffer_.resize(length + 1); - length = - MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, &buffer_[0], length); - if (length == 0) FMT_THROW(WindowsError(GetLastError(), ERROR_MSG)); - buffer_[length] = 0; -} - -FMT_FUNC -fmt::internal::UTF16ToUTF8::UTF16ToUTF8(fmt::WStringRef s) { - if (int error_code = convert(s)) { - FMT_THROW(WindowsError(error_code, "cannot convert string from UTF-16 to UTF-8")); - } -} - -FMT_FUNC int -fmt::internal::UTF16ToUTF8::convert(fmt::WStringRef s) { - if (s.size() > INT_MAX) return ERROR_INVALID_PARAMETER; - int s_size = static_cast(s.size()); - int length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s_size, 0, 0, 0, 0); - if (length == 0) return GetLastError(); - buffer_.resize(length + 1); - length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s_size, &buffer_[0], length, 0, 0); - if (length == 0) return GetLastError(); - buffer_[length] = 0; - return 0; -} - -FMT_FUNC void -fmt::WindowsError::init(int err_code, CStringRef format_str, ArgList args) { - error_code_ = err_code; - MemoryWriter w; - internal::format_windows_error(w, err_code, format(format_str, args)); - std::runtime_error& base = *this; - base = std::runtime_error(w.str()); -} - -FMT_FUNC void -fmt::internal::format_windows_error(fmt::Writer& out, - int error_code, - fmt::StringRef message) FMT_NOEXCEPT { - class String { - private: - LPWSTR str_; - - public: - String() : str_() {} - ~String() { LocalFree(str_); } - LPWSTR* - ptr() { - return &str_; - } - LPCWSTR - c_str() const { - return str_; - } - }; - FMT_TRY { - String system_message; - if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - 0, - error_code, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - reinterpret_cast(system_message.ptr()), - 0, - 0)) { - UTF16ToUTF8 utf8_message; - if (utf8_message.convert(system_message.c_str()) == ERROR_SUCCESS) { - out << message << ": " << utf8_message; - return; - } - } - } - FMT_CATCH(...) {} - fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32. -} - -#endif // FMT_USE_WINDOWS_H - -FMT_FUNC void -fmt::internal::format_system_error(fmt::Writer& out, - int error_code, - fmt::StringRef message) FMT_NOEXCEPT { - FMT_TRY { - MemoryBuffer buffer; - buffer.resize(INLINE_BUFFER_SIZE); - for (;;) { - char* system_message = &buffer[0]; - int result = safe_strerror(error_code, system_message, buffer.size()); - if (result == 0) { - out << message << ": " << system_message; - return; - } - if (result != ERANGE) break; // Can't get error message, report error code instead. - buffer.resize(buffer.size() * 2); - } - } - FMT_CATCH(...) {} - fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32. -} - -template -void -fmt::internal::ArgMap::init(const ArgList& args) { - if (!map_.empty()) return; - typedef internal::NamedArg NamedArg; - const NamedArg* named_arg = 0; - bool use_values = args.type(ArgList::MAX_PACKED_ARGS - 1) == internal::Arg::NONE; - if (use_values) { - for (unsigned i = 0; /*nothing*/; ++i) { - internal::Arg::Type arg_type = args.type(i); - switch (arg_type) { - case internal::Arg::NONE: return; - case internal::Arg::NAMED_ARG: - named_arg = static_cast(args.values_[i].pointer); - map_.insert(Pair(named_arg->name, *named_arg)); - break; - default: - /*nothing*/ - ; - } - } - return; - } - for (unsigned i = 0; i != ArgList::MAX_PACKED_ARGS; ++i) { - internal::Arg::Type arg_type = args.type(i); - if (arg_type == internal::Arg::NAMED_ARG) { - named_arg = static_cast(args.args_[i].pointer); - map_.insert(Pair(named_arg->name, *named_arg)); - } - } - for (unsigned i = ArgList::MAX_PACKED_ARGS; /*nothing*/; ++i) { - switch (args.args_[i].type) { - case internal::Arg::NONE: return; - case internal::Arg::NAMED_ARG: - named_arg = static_cast(args.args_[i].pointer); - map_.insert(Pair(named_arg->name, *named_arg)); - break; - default: - /*nothing*/ - ; - } - } -} - -template -void fmt::internal::FixedBuffer::grow(std::size_t) { - FMT_THROW(std::runtime_error("buffer overflow")); -} - -FMT_FUNC Arg -fmt::internal::FormatterBase::do_get_arg(unsigned arg_index, const char*& error) { - Arg arg = args_[arg_index]; - switch (arg.type) { - case Arg::NONE: error = "argument index out of range"; break; - case Arg::NAMED_ARG: arg = *static_cast(arg.pointer); - default: - /*nothing*/ - ; - } - return arg; -} - -template -void -fmt::internal::PrintfFormatter::parse_flags(FormatSpec& spec, const Char*& s) { - for (;;) { - switch (*s++) { - case '-': spec.align_ = ALIGN_LEFT; break; - case '+': spec.flags_ |= SIGN_FLAG | PLUS_FLAG; break; - case '0': spec.fill_ = '0'; break; - case ' ': spec.flags_ |= SIGN_FLAG; break; - case '#': spec.flags_ |= HASH_FLAG; break; - default: --s; return; - } - } -} - -template -Arg -fmt::internal::PrintfFormatter::get_arg(const Char* s, unsigned arg_index) { - (void)s; - const char* error = 0; - Arg arg = - arg_index == UINT_MAX ? next_arg(error) : FormatterBase::get_arg(arg_index - 1, error); - if (error) FMT_THROW(FormatError(!*s ? "invalid format string" : error)); - return arg; -} - -template -unsigned -fmt::internal::PrintfFormatter::parse_header(const Char*& s, FormatSpec& spec) { - unsigned arg_index = UINT_MAX; - Char c = *s; - if (c >= '0' && c <= '9') { - // Parse an argument index (if followed by '$') or a width possibly - // preceded with '0' flag(s). - unsigned value = parse_nonnegative_int(s); - if (*s == '$') { // value is an argument index - ++s; - arg_index = value; - } else { - if (c == '0') spec.fill_ = '0'; - if (value != 0) { - // Nonzero value means that we parsed width and don't need to - // parse it or flags again, so return now. - spec.width_ = value; - return arg_index; - } - } - } - parse_flags(spec, s); - // Parse width. - if (*s >= '0' && *s <= '9') { - spec.width_ = parse_nonnegative_int(s); - } else if (*s == '*') { - ++s; - spec.width_ = WidthHandler(spec).visit(get_arg(s)); - } - return arg_index; -} - -template -void -fmt::internal::PrintfFormatter::format(BasicWriter& writer, - BasicCStringRef format_str) { - const Char* start = format_str.c_str(); - const Char* s = start; - while (*s) { - Char c = *s++; - if (c != '%') continue; - if (*s == c) { - write(writer, start, s); - start = ++s; - continue; - } - write(writer, start, s - 1); - - FormatSpec spec; - spec.align_ = ALIGN_RIGHT; - - // Parse argument index, flags and width. - unsigned arg_index = parse_header(s, spec); - - // Parse precision. - if (*s == '.') { - ++s; - if ('0' <= *s && *s <= '9') { - spec.precision_ = parse_nonnegative_int(s); - } else if (*s == '*') { - ++s; - spec.precision_ = PrecisionHandler().visit(get_arg(s)); - } - } - - Arg arg = get_arg(s, arg_index); - if (spec.flag(HASH_FLAG) && IsZeroInt().visit(arg)) spec.flags_ &= ~HASH_FLAG; - if (spec.fill_ == '0') { - if (arg.type <= Arg::LAST_NUMERIC_TYPE) - spec.align_ = ALIGN_NUMERIC; - else - spec.fill_ = ' '; // Ignore '0' flag for non-numeric types. - } - - // Parse length and convert the argument to the required type. - switch (*s++) { - case 'h': - if (*s == 'h') - ArgConverter(arg, *++s).visit(arg); - else - ArgConverter(arg, *s).visit(arg); - break; - case 'l': - if (*s == 'l') - ArgConverter(arg, *++s).visit(arg); - else - ArgConverter(arg, *s).visit(arg); - break; - case 'j': ArgConverter(arg, *s).visit(arg); break; - case 'z': ArgConverter(arg, *s).visit(arg); break; - case 't': ArgConverter(arg, *s).visit(arg); break; - case 'L': - // printf produces garbage when 'L' is omitted for long double, no - // need to do the same. - break; - default: --s; ArgConverter(arg, *s).visit(arg); - } - - // Parse type. - if (!*s) FMT_THROW(FormatError("invalid format string")); - spec.type_ = static_cast(*s++); - if (arg.type <= Arg::LAST_INTEGER_TYPE) { - // Normalize type. - switch (spec.type_) { - case 'i': - case 'u': spec.type_ = 'd'; break; - case 'c': - // TODO: handle wchar_t - CharConverter(arg).visit(arg); - break; - } - } - - start = s; - - // Format argument. - internal::PrintfArgFormatter(writer, spec).visit(arg); - } - write(writer, start, s); -} - -FMT_FUNC void -fmt::report_system_error(int error_code, fmt::StringRef message) FMT_NOEXCEPT { - // 'fmt::' is for bcc32. - fmt::report_error(internal::format_system_error, error_code, message); -} - -#if FMT_USE_WINDOWS_H -FMT_FUNC void -fmt::report_windows_error(int error_code, fmt::StringRef message) FMT_NOEXCEPT { - // 'fmt::' is for bcc32. - fmt::report_error(internal::format_windows_error, error_code, message); -} -#endif - -FMT_FUNC void -fmt::print(std::FILE* f, CStringRef format_str, ArgList args) { - MemoryWriter w; - w.write(format_str, args); - std::fwrite(w.data(), 1, w.size(), f); -} - -FMT_FUNC void -fmt::print(CStringRef format_str, ArgList args) { - print(stdout, format_str, args); -} - -FMT_FUNC void -fmt::print(std::ostream& os, CStringRef format_str, ArgList args) { - MemoryWriter w; - w.write(format_str, args); - os.write(w.data(), w.size()); -} - -FMT_FUNC void -fmt::print_colored(Color c, CStringRef format, ArgList args) { - char escape[] = "\x1b[30m"; - escape[3] = static_cast('0' + c); - std::fputs(escape, stdout); - print(format, args); - std::fputs(RESET_COLOR, stdout); -} - -FMT_FUNC int -fmt::fprintf(std::FILE* f, CStringRef format, ArgList args) { - MemoryWriter w; - printf(w, format, args); - std::size_t size = w.size(); - return std::fwrite(w.data(), 1, size, f) < size ? -1 : static_cast(size); -} - -#ifndef FMT_HEADER_ONLY - -template struct fmt::internal::BasicData; - -// Explicit instantiations for char. - -template void fmt::internal::FixedBuffer::grow(std::size_t); - -template void fmt::internal::ArgMap::init(const fmt::ArgList& args); - -template void fmt::internal::PrintfFormatter::format(BasicWriter& writer, - CStringRef format); - -template int fmt::internal::CharTraits::format_float(char* buffer, - std::size_t size, - const char* format, - unsigned width, - int precision, - double value); - -template int fmt::internal::CharTraits::format_float(char* buffer, - std::size_t size, - const char* format, - unsigned width, - int precision, - long double value); - -// Explicit instantiations for wchar_t. - -template void fmt::internal::FixedBuffer::grow(std::size_t); - -template void fmt::internal::ArgMap::init(const fmt::ArgList& args); - -template void fmt::internal::PrintfFormatter::format(BasicWriter& writer, - WCStringRef format); - -template int fmt::internal::CharTraits::format_float(wchar_t* buffer, - std::size_t size, - const wchar_t* format, - unsigned width, - int precision, - double value); - -template int fmt::internal::CharTraits::format_float(wchar_t* buffer, - std::size_t size, - const wchar_t* format, - unsigned width, - int precision, - long double value); - -#endif // FMT_HEADER_ONLY - -#ifdef _MSC_VER -#pragma warning(pop) -#endif \ No newline at end of file diff --git a/cameradar_standalone/include/spdlog/details/format.h b/cameradar_standalone/include/spdlog/details/format.h deleted file mode 100644 index 960e927..0000000 --- a/cameradar_standalone/include/spdlog/details/format.h +++ /dev/null @@ -1,3852 +0,0 @@ -/* -Formatting library for C++ - -Copyright (c) 2012 - 2015, Victor Zverovich -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this -list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright notice, -this list of conditions and the following disclaimer in the documentation -and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef FMT_FORMAT_H_ -#define FMT_FORMAT_H_ - -#define FMT_HEADER_ONLY // Added by spdlog for header only usage - -#if defined _MSC_VER && _MSC_VER <= 1500 -typedef unsigned int uint32_t; -typedef unsigned long long uint64_t; -typedef long long intmax_t; -#else -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifndef FMT_USE_IOSTREAMS -#define FMT_USE_IOSTREAMS 1 -#endif - -#if FMT_USE_IOSTREAMS -#include -#endif - -#ifdef _SECURE_SCL -#define FMT_SECURE_SCL _SECURE_SCL -#else -#define FMT_SECURE_SCL 0 -#endif - -#if FMT_SECURE_SCL -#include -#endif - -#if !defined(FMT_HEADER_ONLY) && defined(_WIN32) -#ifdef FMT_EXPORT -#define FMT_API __declspec(dllexport) -#elif defined(FMT_SHARED) -#define FMT_API __declspec(dllimport) -#endif -#endif -#ifndef FMT_API -#define FMT_API -#endif - -#ifdef _MSC_VER -#include // _BitScanReverse, _BitScanReverse64 - -namespace fmt { -namespace internal { -#pragma intrinsic(_BitScanReverse) -inline uint32_t -clz(uint32_t x) { - unsigned long r = 0; - _BitScanReverse(&r, x); - return 31 - r; -} -#define FMT_BUILTIN_CLZ(n) fmt::internal::clz(n) - -#ifdef _WIN64 -#pragma intrinsic(_BitScanReverse64) -#endif - -inline uint32_t -clzll(uint64_t x) { - unsigned long r = 0; -#ifdef _WIN64 - _BitScanReverse64(&r, x); -#else - // Scan the high 32 bits. - if (_BitScanReverse(&r, static_cast(x >> 32))) return 63 - (r + 32); - - // Scan the low 32 bits. - _BitScanReverse(&r, static_cast(x)); -#endif - return 63 - r; -} -#define FMT_BUILTIN_CLZLL(n) fmt::internal::clzll(n) -} -} -#endif - -#ifdef __GNUC__ -#define FMT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) -#define FMT_GCC_EXTENSION __extension__ -#if FMT_GCC_VERSION >= 406 -#pragma GCC diagnostic push -// Disable the warning about "long long" which is sometimes reported even -// when using __extension__. -#pragma GCC diagnostic ignored "-Wlong-long" -// Disable the warning about declaration shadowing because it affects too -// many valid cases. -#pragma GCC diagnostic ignored "-Wshadow" -// Disable the warning about implicit conversions that may change the sign of -// an integer; silencing it otherwise would require many explicit casts. -#pragma GCC diagnostic ignored "-Wsign-conversion" -#endif -#if __cplusplus >= 201103L || defined __GXX_EXPERIMENTAL_CXX0X__ -#define FMT_HAS_GXX_CXX11 1 -#endif -#else -#define FMT_GCC_EXTENSION -#endif - -#if defined(__clang__) && !defined(__INTEL_COMPILER) -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdocumentation" -#endif - -#ifdef __GNUC_LIBSTD__ -#define FMT_GNUC_LIBSTD_VERSION (__GNUC_LIBSTD__ * 100 + __GNUC_LIBSTD_MINOR__) -#endif - -#ifdef __has_feature -#define FMT_HAS_FEATURE(x) __has_feature(x) -#else -#define FMT_HAS_FEATURE(x) 0 -#endif - -#ifdef __has_builtin -#define FMT_HAS_BUILTIN(x) __has_builtin(x) -#else -#define FMT_HAS_BUILTIN(x) 0 -#endif - -#ifdef __has_cpp_attribute -#define FMT_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x) -#else -#define FMT_HAS_CPP_ATTRIBUTE(x) 0 -#endif - -#ifndef FMT_USE_VARIADIC_TEMPLATES -// Variadic templates are available in GCC since version 4.4 -// (http://gcc.gnu.org/projects/cxx0x.html) and in Visual C++ -// since version 2013. -#define FMT_USE_VARIADIC_TEMPLATES \ - (FMT_HAS_FEATURE(cxx_variadic_templates) || (FMT_GCC_VERSION >= 404 && FMT_HAS_GXX_CXX11) || \ - _MSC_VER >= 1800) -#endif - -#ifndef FMT_USE_RVALUE_REFERENCES -// Don't use rvalue references when compiling with clang and an old libstdc++ -// as the latter doesn't provide std::move. -#if defined(FMT_GNUC_LIBSTD_VERSION) && FMT_GNUC_LIBSTD_VERSION <= 402 -#define FMT_USE_RVALUE_REFERENCES 0 -#else -#define FMT_USE_RVALUE_REFERENCES \ - (FMT_HAS_FEATURE(cxx_rvalue_references) || (FMT_GCC_VERSION >= 403 && FMT_HAS_GXX_CXX11) || \ - _MSC_VER >= 1600) -#endif -#endif - -#if FMT_USE_RVALUE_REFERENCES -#include // for std::move -#endif - -// Define FMT_USE_NOEXCEPT to make C++ Format use noexcept (C++11 feature). -#ifndef FMT_USE_NOEXCEPT -#define FMT_USE_NOEXCEPT 0 -#endif - -#ifndef FMT_NOEXCEPT -#if FMT_USE_NOEXCEPT || FMT_HAS_FEATURE(cxx_noexcept) || \ - (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || _MSC_VER >= 1900 -#define FMT_NOEXCEPT noexcept -#else -#define FMT_NOEXCEPT throw() -#endif -#endif - -// Check if exceptions are disabled. -#if defined(__GNUC__) && !defined(__EXCEPTIONS) -#define FMT_EXCEPTIONS 0 -#endif -#if defined(_MSC_VER) && !_HAS_EXCEPTIONS -#define FMT_EXCEPTIONS 0 -#endif -#ifndef FMT_EXCEPTIONS -#define FMT_EXCEPTIONS 1 -#endif - -#ifndef FMT_THROW -#if FMT_EXCEPTIONS -#define FMT_THROW(x) throw x -#else -#define FMT_THROW(x) assert(false) -#endif -#endif - -// A macro to disallow the copy constructor and operator= functions -// This should be used in the private: declarations for a class -#ifndef FMT_USE_DELETED_FUNCTIONS -#define FMT_USE_DELETED_FUNCTIONS 0 -#endif - -#if FMT_USE_DELETED_FUNCTIONS || FMT_HAS_FEATURE(cxx_deleted_functions) || \ - (FMT_GCC_VERSION >= 404 && FMT_HAS_GXX_CXX11) || _MSC_VER >= 1800 -#define FMT_DELETED_OR_UNDEFINED = delete -#define FMT_DISALLOW_COPY_AND_ASSIGN(TypeName) \ - TypeName(const TypeName&) = delete; \ - TypeName& operator=(const TypeName&) = delete -#else -#define FMT_DELETED_OR_UNDEFINED -#define FMT_DISALLOW_COPY_AND_ASSIGN(TypeName) \ - TypeName(const TypeName&); \ - TypeName& operator=(const TypeName&) -#endif - -#ifndef FMT_USE_USER_DEFINED_LITERALS -// All compilers which support UDLs also support variadic templates. This -// makes the fmt::literals implementation easier. However, an explicit check -// for variadic templates is added here just in case. -#define FMT_USE_USER_DEFINED_LITERALS \ - FMT_USE_VARIADIC_TEMPLATES&& FMT_USE_RVALUE_REFERENCES && \ - (FMT_HAS_FEATURE(cxx_user_literals) || (FMT_GCC_VERSION >= 407 && FMT_HAS_GXX_CXX11) || \ - _MSC_VER >= 1900) -#endif - -#ifndef FMT_ASSERT -#define FMT_ASSERT(condition, message) assert((condition) && message) -#endif - -namespace fmt { -namespace internal { -struct DummyInt { - int data[2]; - operator int() const { return 0; } -}; -typedef std::numeric_limits FPUtil; - -// Dummy implementations of system functions such as signbit and ecvt called -// if the latter are not available. -inline DummyInt signbit(...) { return DummyInt(); } -inline DummyInt _ecvt_s(...) { return DummyInt(); } -inline DummyInt isinf(...) { return DummyInt(); } -inline DummyInt _finite(...) { return DummyInt(); } -inline DummyInt isnan(...) { return DummyInt(); } -inline DummyInt _isnan(...) { return DummyInt(); } - -// A helper function to suppress bogus "conditional expression is constant" -// warnings. -template -inline T -check(T value) { - return value; -} -} -} // namespace fmt - -namespace std { -// Standard permits specialization of std::numeric_limits. This specialization -// is used to resolve ambiguity between isinf and std::isinf in glibc: -// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=48891 -// and the same for isnan and signbit. -template <> -class numeric_limits : public std::numeric_limits { -public: - // Portable version of isinf. - template - static bool - isinfinity(T x) { - using namespace fmt::internal; - // The resolution "priority" is: - // isinf macro > std::isinf > ::isinf > fmt::internal::isinf - if (check(sizeof(isinf(x)) == sizeof(bool) || sizeof(isinf(x)) == sizeof(int))) { - return isinf(x) != 0; - } - return !_finite(static_cast(x)); - } - - // Portable version of isnan. - template - static bool - isnotanumber(T x) { - using namespace fmt::internal; - if (check(sizeof(isnan(x)) == sizeof(bool) || sizeof(isnan(x)) == sizeof(int))) { - return isnan(x) != 0; - } - return _isnan(static_cast(x)) != 0; - } - - // Portable version of signbit. - static bool - isnegative(double x) { - using namespace fmt::internal; - if (check(sizeof(signbit(x)) == sizeof(int))) return signbit(x) != 0; - if (x < 0) return true; - if (!isnotanumber(x)) return false; - int dec = 0, sign = 0; - char buffer[2]; // The buffer size must be >= 2 or _ecvt_s will fail. - _ecvt_s(buffer, sizeof(buffer), x, 0, &dec, &sign); - return sign != 0; - } -}; -} // namespace std - -namespace fmt { - -// Fix the warning about long long on older versions of GCC -// that don't support the diagnostic pragma. -FMT_GCC_EXTENSION typedef long long LongLong; -FMT_GCC_EXTENSION typedef unsigned long long ULongLong; - -#if FMT_USE_RVALUE_REFERENCES -using std::move; -#endif - -template -class BasicWriter; - -typedef BasicWriter Writer; -typedef BasicWriter WWriter; - -template -class BasicFormatter; - -template -void format(BasicFormatter& f, const Char*& format_str, const T& value); - -/** -\rst -A string reference. It can be constructed from a C string or ``std::string``. - -You can use one of the following typedefs for common character types: - -+------------+-------------------------+ -| Type | Definition | -+============+=========================+ -| StringRef | BasicStringRef | -+------------+-------------------------+ -| WStringRef | BasicStringRef | -+------------+-------------------------+ - -This class is most useful as a parameter type to allow passing -different types of strings to a function, for example:: - -template -std::string format(StringRef format_str, const Args & ... args); - -format("{}", 42); -format(std::string("{}"), 42); -\endrst -*/ -template -class BasicStringRef { -private: - const Char* data_; - std::size_t size_; - -public: - /** Constructs a string reference object from a C string and a size. */ - BasicStringRef(const Char* s, std::size_t size) : data_(s), size_(size) {} - - /** - \rst - Constructs a string reference object from a C string computing - the size with ``std::char_traits::length``. - \endrst - */ - BasicStringRef(const Char* s) : data_(s), size_(std::char_traits::length(s)) {} - - /** - \rst - Constructs a string reference from an ``std::string`` object. - \endrst - */ - BasicStringRef(const std::basic_string& s) : data_(s.c_str()), size_(s.size()) {} - - /** - \rst - Converts a string reference to an ``std::string`` object. - \endrst - */ - std::basic_string - to_string() const { - return std::basic_string(data_, size_); - } - - /** Returns the pointer to a C string. */ - const Char* - data() const { - return data_; - } - - /** Returns the string size. */ - std::size_t - size() const { - return size_; - } - - // Lexicographically compare this string reference to other. - int - compare(BasicStringRef other) const { - std::size_t size = size_ < other.size_ ? size_ : other.size_; - int result = std::char_traits::compare(data_, other.data_, size); - if (result == 0) result = size_ == other.size_ ? 0 : (size_ < other.size_ ? -1 : 1); - return result; - } - - friend bool operator==(BasicStringRef lhs, BasicStringRef rhs) { return lhs.compare(rhs) == 0; } - friend bool operator!=(BasicStringRef lhs, BasicStringRef rhs) { return lhs.compare(rhs) != 0; } - friend bool operator<(BasicStringRef lhs, BasicStringRef rhs) { return lhs.compare(rhs) < 0; } - friend bool operator<=(BasicStringRef lhs, BasicStringRef rhs) { return lhs.compare(rhs) <= 0; } - friend bool operator>(BasicStringRef lhs, BasicStringRef rhs) { return lhs.compare(rhs) > 0; } - friend bool operator>=(BasicStringRef lhs, BasicStringRef rhs) { return lhs.compare(rhs) >= 0; } -}; - -typedef BasicStringRef StringRef; -typedef BasicStringRef WStringRef; - -/** -\rst -A reference to a null terminated string. It can be constructed from a C -string or ``std::string``. - -You can use one of the following typedefs for common character types: - -+-------------+--------------------------+ -| Type | Definition | -+=============+==========================+ -| CStringRef | BasicCStringRef | -+-------------+--------------------------+ -| WCStringRef | BasicCStringRef | -+-------------+--------------------------+ - -This class is most useful as a parameter type to allow passing -different types of strings to a function, for example:: - -template -std::string format(CStringRef format_str, const Args & ... args); - -format("{}", 42); -format(std::string("{}"), 42); -\endrst -*/ -template -class BasicCStringRef { -private: - const Char* data_; - -public: - /** Constructs a string reference object from a C string. */ - BasicCStringRef(const Char* s) : data_(s) {} - - /** - \rst - Constructs a string reference from an ``std::string`` object. - \endrst - */ - BasicCStringRef(const std::basic_string& s) : data_(s.c_str()) {} - - /** Returns the pointer to a C string. */ - const Char* - c_str() const { - return data_; - } -}; - -typedef BasicCStringRef CStringRef; -typedef BasicCStringRef WCStringRef; - -/** -A formatting error such as invalid format string. -*/ -class FormatError : public std::runtime_error { -public: - explicit FormatError(CStringRef message) : std::runtime_error(message.c_str()) {} -}; - -namespace internal { -// The number of characters to store in the MemoryBuffer object itself -// to avoid dynamic memory allocation. -enum { INLINE_BUFFER_SIZE = 500 }; - -#if FMT_SECURE_SCL -// Use checked iterator to avoid warnings on MSVC. -template -inline stdext::checked_array_iterator -make_ptr(T* ptr, std::size_t size) { - return stdext::checked_array_iterator(ptr, size); -} -#else -template -inline T* -make_ptr(T* ptr, std::size_t) { - return ptr; -} -#endif -} // namespace internal - -/** -\rst -A buffer supporting a subset of ``std::vector``'s operations. -\endrst -*/ -template -class Buffer { -private: - FMT_DISALLOW_COPY_AND_ASSIGN(Buffer); - -protected: - T* ptr_; - std::size_t size_; - std::size_t capacity_; - - Buffer(T* ptr = 0, std::size_t capacity = 0) : ptr_(ptr), size_(0), capacity_(capacity) {} - - /** - \rst - Increases the buffer capacity to hold at least *size* elements updating - ``ptr_`` and ``capacity_``. - \endrst - */ - virtual void grow(std::size_t size) = 0; - -public: - virtual ~Buffer() {} - - /** Returns the size of this buffer. */ - std::size_t - size() const { - return size_; - } - - /** Returns the capacity of this buffer. */ - std::size_t - capacity() const { - return capacity_; - } - - /** - Resizes the buffer. If T is a POD type new elements may not be initialized. - */ - void - resize(std::size_t new_size) { - if (new_size > capacity_) grow(new_size); - size_ = new_size; - } - - /** - \rst - Reserves space to store at least *capacity* elements. - \endrst - */ - void - reserve(std::size_t capacity) { - if (capacity > capacity_) grow(capacity); - } - - void - clear() FMT_NOEXCEPT { - size_ = 0; - } - - void - push_back(const T& value) { - if (size_ == capacity_) grow(size_ + 1); - ptr_[size_++] = value; - } - - /** Appends data to the end of the buffer. */ - template - void append(const U* begin, const U* end); - - T& operator[](std::size_t index) { return ptr_[index]; } - const T& operator[](std::size_t index) const { return ptr_[index]; } -}; - -template -template -void -Buffer::append(const U* begin, const U* end) { - assert(begin <= end); - std::size_t new_size = size_ + (end - begin); - if (new_size > capacity_) grow(new_size); - std::uninitialized_copy(begin, end, internal::make_ptr(ptr_, capacity_) + size_); - size_ = new_size; -} - -namespace internal { - -// A memory buffer for POD types with the first SIZE elements stored in -// the object itself. -template > -class MemoryBuffer : private Allocator, public Buffer { -private: - T data_[SIZE]; - - // Deallocate memory allocated by the buffer. - void - deallocate() { - if (this->ptr_ != data_) Allocator::deallocate(this->ptr_, this->capacity_); - } - -protected: - void grow(std::size_t size); - -public: - explicit MemoryBuffer(const Allocator& alloc = Allocator()) - : Allocator(alloc), Buffer(data_, SIZE) {} - ~MemoryBuffer() { deallocate(); } - -#if FMT_USE_RVALUE_REFERENCES -private: - // Move data from other to this buffer. - void - move(MemoryBuffer& other) { - Allocator &this_alloc = *this, &other_alloc = other; - this_alloc = std::move(other_alloc); - this->size_ = other.size_; - this->capacity_ = other.capacity_; - if (other.ptr_ == other.data_) { - this->ptr_ = data_; - std::uninitialized_copy( - other.data_, other.data_ + this->size_, make_ptr(data_, this->capacity_)); - } else { - this->ptr_ = other.ptr_; - // Set pointer to the inline array so that delete is not called - // when deallocating. - other.ptr_ = other.data_; - } - } - -public: - MemoryBuffer(MemoryBuffer&& other) { move(other); } - - MemoryBuffer& operator=(MemoryBuffer&& other) { - assert(this != &other); - deallocate(); - move(other); - return *this; - } -#endif - - // Returns a copy of the allocator associated with this buffer. - Allocator - get_allocator() const { - return *this; - } -}; - -template -void -MemoryBuffer::grow(std::size_t size) { - std::size_t new_capacity = this->capacity_ + this->capacity_ / 2; - if (size > new_capacity) new_capacity = size; - T* new_ptr = this->allocate(new_capacity); - // The following code doesn't throw, so the raw pointer above doesn't leak. - std::uninitialized_copy(this->ptr_, this->ptr_ + this->size_, make_ptr(new_ptr, new_capacity)); - std::size_t old_capacity = this->capacity_; - T* old_ptr = this->ptr_; - this->capacity_ = new_capacity; - this->ptr_ = new_ptr; - // deallocate may throw (at least in principle), but it doesn't matter since - // the buffer already uses the new storage and will deallocate it in case - // of exception. - if (old_ptr != data_) Allocator::deallocate(old_ptr, old_capacity); -} - -// A fixed-size buffer. -template -class FixedBuffer : public fmt::Buffer { -public: - FixedBuffer(Char* array, std::size_t size) : fmt::Buffer(array, size) {} - -protected: - FMT_API void grow(std::size_t size); -}; - -template -class BasicCharTraits { -public: -#if FMT_SECURE_SCL - typedef stdext::checked_array_iterator CharPtr; -#else - typedef Char* CharPtr; -#endif - static Char - cast(int value) { - return static_cast(value); - } -}; - -template -class CharTraits; - -template <> -class CharTraits : public BasicCharTraits { -private: - // Conversion from wchar_t to char is not allowed. - static char convert(wchar_t); - -public: - static char - convert(char value) { - return value; - } - - // Formats a floating-point number. - template - FMT_API static int format_float( - char* buffer, std::size_t size, const char* format, unsigned width, int precision, T value); -}; - -template <> -class CharTraits : public BasicCharTraits { -public: - static wchar_t - convert(char value) { - return value; - } - static wchar_t - convert(wchar_t value) { - return value; - } - - template - FMT_API static int format_float(wchar_t* buffer, - std::size_t size, - const wchar_t* format, - unsigned width, - int precision, - T value); -}; - -// Checks if a number is negative - used to avoid warnings. -template -struct SignChecker { - template - static bool - is_negative(T value) { - return value < 0; - } -}; - -template <> -struct SignChecker { - template - static bool is_negative(T) { - return false; - } -}; - -// Returns true if value is negative, false otherwise. -// Same as (value < 0) but doesn't produce warnings if T is an unsigned type. -template -inline bool -is_negative(T value) { - return SignChecker::is_signed>::is_negative(value); -} - -// Selects uint32_t if FitsIn32Bits is true, uint64_t otherwise. -template -struct TypeSelector { - typedef uint32_t Type; -}; - -template <> -struct TypeSelector { - typedef uint64_t Type; -}; - -template -struct IntTraits { - // Smallest of uint32_t and uint64_t that is large enough to represent - // all values of T. - typedef typename TypeSelector::digits <= 32>::Type MainType; -}; - -// MakeUnsigned::Type gives an unsigned type corresponding to integer type T. -template -struct MakeUnsigned { - typedef T Type; -}; - -#define FMT_SPECIALIZE_MAKE_UNSIGNED(T, U) \ - template <> \ - struct MakeUnsigned { \ - typedef U Type; \ - } - -FMT_SPECIALIZE_MAKE_UNSIGNED(char, unsigned char); -FMT_SPECIALIZE_MAKE_UNSIGNED(signed char, unsigned char); -FMT_SPECIALIZE_MAKE_UNSIGNED(short, unsigned short); -FMT_SPECIALIZE_MAKE_UNSIGNED(int, unsigned); -FMT_SPECIALIZE_MAKE_UNSIGNED(long, unsigned long); -FMT_SPECIALIZE_MAKE_UNSIGNED(LongLong, ULongLong); - -FMT_API void report_unknown_type(char code, const char* type); - -// Static data is placed in this class template to allow header-only -// configuration. -template -struct FMT_API BasicData { - static const uint32_t POWERS_OF_10_32[]; - static const uint64_t POWERS_OF_10_64[]; - static const char DIGITS[]; -}; - -typedef BasicData<> Data; - -#if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clz) -#define FMT_BUILTIN_CLZ(n) __builtin_clz(n) -#endif - -#if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clzll) -#define FMT_BUILTIN_CLZLL(n) __builtin_clzll(n) -#endif - -#ifdef FMT_BUILTIN_CLZLL -// Returns the number of decimal digits in n. Leading zeros are not counted -// except for n == 0 in which case count_digits returns 1. -inline unsigned -count_digits(uint64_t n) { - // Based on http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10 - // and the benchmark https://github.com/localvoid/cxx-benchmark-count-digits. - unsigned t = (64 - FMT_BUILTIN_CLZLL(n | 1)) * 1233 >> 12; - return t - (n < Data::POWERS_OF_10_64[t]) + 1; -} -#else -// Fallback version of count_digits used when __builtin_clz is not available. -inline unsigned -count_digits(uint64_t n) { - unsigned count = 1; - for (;;) { - // Integer division is slow so do it for a group of four digits instead - // of for every digit. The idea comes from the talk by Alexandrescu - // "Three Optimization Tips for C++". See speed-test for a comparison. - if (n < 10) return count; - if (n < 100) return count + 1; - if (n < 1000) return count + 2; - if (n < 10000) return count + 3; - n /= 10000u; - count += 4; - } -} -#endif - -#ifdef FMT_BUILTIN_CLZ -// Optional version of count_digits for better performance on 32-bit platforms. -inline unsigned -count_digits(uint32_t n) { - uint32_t t = (32 - FMT_BUILTIN_CLZ(n | 1)) * 1233 >> 12; - return t - (n < Data::POWERS_OF_10_32[t]) + 1; -} -#endif - -// Formats a decimal unsigned integer value writing into buffer. -template -inline void -format_decimal(Char* buffer, UInt value, unsigned num_digits) { - buffer += num_digits; - while (value >= 100) { - // Integer division is slow so do it for a group of two digits instead - // of for every digit. The idea comes from the talk by Alexandrescu - // "Three Optimization Tips for C++". See speed-test for a comparison. - unsigned index = static_cast((value % 100) * 2); - value /= 100; - *--buffer = Data::DIGITS[index + 1]; - *--buffer = Data::DIGITS[index]; - } - if (value < 10) { - *--buffer = static_cast('0' + value); - return; - } - unsigned index = static_cast(value * 2); - *--buffer = Data::DIGITS[index + 1]; - *--buffer = Data::DIGITS[index]; -} - -#ifndef _WIN32 -#define FMT_USE_WINDOWS_H 0 -#elif !defined(FMT_USE_WINDOWS_H) -#define FMT_USE_WINDOWS_H 1 -#endif - -// Define FMT_USE_WINDOWS_H to 0 to disable use of windows.h. -// All the functionality that relies on it will be disabled too. -#if FMT_USE_WINDOWS_H -// A converter from UTF-8 to UTF-16. -// It is only provided for Windows since other systems support UTF-8 natively. -class UTF8ToUTF16 { -private: - MemoryBuffer buffer_; - -public: - FMT_API explicit UTF8ToUTF16(StringRef s); - operator WStringRef() const { return WStringRef(&buffer_[0], size()); } - size_t - size() const { - return buffer_.size() - 1; - } - const wchar_t* - c_str() const { - return &buffer_[0]; - } - std::wstring - str() const { - return std::wstring(&buffer_[0], size()); - } -}; - -// A converter from UTF-16 to UTF-8. -// It is only provided for Windows since other systems support UTF-8 natively. -class UTF16ToUTF8 { -private: - MemoryBuffer buffer_; - -public: - UTF16ToUTF8() {} - FMT_API explicit UTF16ToUTF8(WStringRef s); - operator StringRef() const { return StringRef(&buffer_[0], size()); } - size_t - size() const { - return buffer_.size() - 1; - } - const char* - c_str() const { - return &buffer_[0]; - } - std::string - str() const { - return std::string(&buffer_[0], size()); - } - - // Performs conversion returning a system error code instead of - // throwing exception on conversion error. This method may still throw - // in case of memory allocation error. - FMT_API int convert(WStringRef s); -}; - -FMT_API void -format_windows_error(fmt::Writer& out, int error_code, fmt::StringRef message) FMT_NOEXCEPT; -#endif - -FMT_API void -format_system_error(fmt::Writer& out, int error_code, fmt::StringRef message) FMT_NOEXCEPT; - -// A formatting argument value. -struct Value { - template - struct StringValue { - const Char* value; - std::size_t size; - }; - - typedef void (*FormatFunc)(void* formatter, const void* arg, void* format_str_ptr); - - struct CustomValue { - const void* value; - FormatFunc format; - }; - - union { - int int_value; - unsigned uint_value; - LongLong long_long_value; - ULongLong ulong_long_value; - double double_value; - long double long_double_value; - const void* pointer; - StringValue string; - StringValue sstring; - StringValue ustring; - StringValue wstring; - CustomValue custom; - }; - - enum Type { - NONE, - NAMED_ARG, - // Integer types should go first, - INT, - UINT, - LONG_LONG, - ULONG_LONG, - BOOL, - CHAR, - LAST_INTEGER_TYPE = CHAR, - // followed by floating-point types. - DOUBLE, - LONG_DOUBLE, - LAST_NUMERIC_TYPE = LONG_DOUBLE, - CSTRING, - STRING, - WSTRING, - POINTER, - CUSTOM - }; -}; - -// A formatting argument. It is a POD type to allow storage in -// internal::MemoryBuffer. -struct Arg : Value { - Type type; -}; - -template -struct NamedArg; - -template -struct Null {}; - -// A helper class template to enable or disable overloads taking wide -// characters and strings in MakeValue. -template -struct WCharHelper { - typedef Null Supported; - typedef T Unsupported; -}; - -template -struct WCharHelper { - typedef T Supported; - typedef Null Unsupported; -}; - -typedef char Yes[1]; -typedef char No[2]; - -// These are non-members to workaround an overload resolution bug in bcc32. -Yes& convert(fmt::ULongLong); -Yes& convert(std::ostream&); -No& convert(...); - -template -T& get(); - -struct DummyStream : std::ostream { - DummyStream(); // Suppress a bogus warning in MSVC. - // Hide all operator<< overloads from std::ostream. - void operator<<(Null<>); -}; - -No& operator<<(std::ostream&, int); - -template -struct ConvertToIntImpl { - enum { value = false }; -}; - -template -struct ConvertToIntImpl { - // Convert to int only if T doesn't have an overloaded operator<<. - enum { value = sizeof(convert(get() << get())) == sizeof(No) }; -}; - -template -struct ConvertToIntImpl2 { - enum { value = false }; -}; - -template -struct ConvertToIntImpl2 { - enum { - // Don't convert numeric types. - value = ConvertToIntImpl::is_specialized>::value - }; -}; - -template -struct ConvertToInt { - enum { enable_conversion = sizeof(convert(get())) == sizeof(Yes) }; - enum { value = ConvertToIntImpl2::value }; -}; - -#define FMT_DISABLE_CONVERSION_TO_INT(Type) \ - template <> \ - struct ConvertToInt { \ - enum { value = 0 }; \ - } - -// Silence warnings about convering float to int. -FMT_DISABLE_CONVERSION_TO_INT(float); -FMT_DISABLE_CONVERSION_TO_INT(double); -FMT_DISABLE_CONVERSION_TO_INT(long double); - -template -struct EnableIf {}; - -template -struct EnableIf { - typedef T type; -}; - -template -struct Conditional { - typedef T type; -}; - -template -struct Conditional { - typedef F type; -}; - -// For bcc32 which doesn't understand ! in template arguments. -template -struct Not { - enum { value = 0 }; -}; - -template <> -struct Not { - enum { value = 1 }; -}; - -// Makes an Arg object from any type. -template -class MakeValue : public Arg { -public: - typedef typename Formatter::Char Char; - -private: - // The following two methods are private to disallow formatting of - // arbitrary pointers. If you want to output a pointer cast it to - // "void *" or "const void *". In particular, this forbids formatting - // of "[const] volatile char *" which is printed as bool by iostreams. - // Do not implement! - template - MakeValue(const T* value); - template - MakeValue(T* value); - -// The following methods are private to disallow formatting of wide -// characters and strings into narrow strings as in -// fmt::format("{}", L"test"); -// To fix this, use a wide format string: fmt::format(L"{}", L"test"). -#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) - MakeValue(typename WCharHelper::Unsupported); -#endif - MakeValue(typename WCharHelper::Unsupported); - MakeValue(typename WCharHelper::Unsupported); - MakeValue(typename WCharHelper::Unsupported); - MakeValue(typename WCharHelper::Unsupported); - - void - set_string(StringRef str) { - string.value = str.data(); - string.size = str.size(); - } - - void - set_string(WStringRef str) { - wstring.value = str.data(); - wstring.size = str.size(); - } - - // Formats an argument of a custom type, such as a user-defined class. - template - static void - format_custom_arg(void* formatter, const void* arg, void* format_str_ptr) { - format(*static_cast(formatter), - *static_cast(format_str_ptr), - *static_cast(arg)); - } - -public: - MakeValue() {} - -#define FMT_MAKE_VALUE_(Type, field, TYPE, rhs) \ - MakeValue(Type value) { field = rhs; } \ - static uint64_t type(Type) { return Arg::TYPE; } - -#define FMT_MAKE_VALUE(Type, field, TYPE) FMT_MAKE_VALUE_(Type, field, TYPE, value) - - FMT_MAKE_VALUE(bool, int_value, BOOL) - FMT_MAKE_VALUE(short, int_value, INT) - FMT_MAKE_VALUE(unsigned short, uint_value, UINT) - FMT_MAKE_VALUE(int, int_value, INT) - FMT_MAKE_VALUE(unsigned, uint_value, UINT) - - MakeValue(long value) { - // To minimize the number of types we need to deal with, long is - // translated either to int or to long long depending on its size. - if (check(sizeof(long) == sizeof(int))) - int_value = static_cast(value); - else - long_long_value = value; - } - static uint64_t - type(long) { - return sizeof(long) == sizeof(int) ? Arg::INT : Arg::LONG_LONG; - } - - MakeValue(unsigned long value) { - if (check(sizeof(unsigned long) == sizeof(unsigned))) - uint_value = static_cast(value); - else - ulong_long_value = value; - } - static uint64_t - type(unsigned long) { - return sizeof(unsigned long) == sizeof(unsigned) ? Arg::UINT : Arg::ULONG_LONG; - } - - FMT_MAKE_VALUE(LongLong, long_long_value, LONG_LONG) - FMT_MAKE_VALUE(ULongLong, ulong_long_value, ULONG_LONG) - FMT_MAKE_VALUE(float, double_value, DOUBLE) - FMT_MAKE_VALUE(double, double_value, DOUBLE) - FMT_MAKE_VALUE(long double, long_double_value, LONG_DOUBLE) - FMT_MAKE_VALUE(signed char, int_value, INT) - FMT_MAKE_VALUE(unsigned char, uint_value, UINT) - FMT_MAKE_VALUE(char, int_value, CHAR) - -#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) - MakeValue(typename WCharHelper::Supported value) { int_value = value; } - static uint64_t type(wchar_t) { return Arg::CHAR; } -#endif - -#define FMT_MAKE_STR_VALUE(Type, TYPE) \ - MakeValue(Type value) { set_string(value); } \ - static uint64_t type(Type) { return Arg::TYPE; } - - FMT_MAKE_VALUE(char*, string.value, CSTRING) - FMT_MAKE_VALUE(const char*, string.value, CSTRING) - FMT_MAKE_VALUE(const signed char*, sstring.value, CSTRING) - FMT_MAKE_VALUE(const unsigned char*, ustring.value, CSTRING) - FMT_MAKE_STR_VALUE(const std::string&, STRING) - FMT_MAKE_STR_VALUE(StringRef, STRING) - FMT_MAKE_VALUE_(CStringRef, string.value, CSTRING, value.c_str()) - -#define FMT_MAKE_WSTR_VALUE(Type, TYPE) \ - MakeValue(typename WCharHelper::Supported value) { set_string(value); } \ - static uint64_t type(Type) { return Arg::TYPE; } - - FMT_MAKE_WSTR_VALUE(wchar_t*, WSTRING) - FMT_MAKE_WSTR_VALUE(const wchar_t*, WSTRING) - FMT_MAKE_WSTR_VALUE(const std::wstring&, WSTRING) - FMT_MAKE_WSTR_VALUE(WStringRef, WSTRING) - - FMT_MAKE_VALUE(void*, pointer, POINTER) - FMT_MAKE_VALUE(const void*, pointer, POINTER) - - template - MakeValue(const T& value, - typename EnableIf::value>::value, int>::type = 0) { - custom.value = &value; - custom.format = &format_custom_arg; - } - - template - MakeValue(const T& value, typename EnableIf::value, int>::type = 0) { - int_value = value; - } - - template - static uint64_t - type(const T&) { - return ConvertToInt::value ? Arg::INT : Arg::CUSTOM; - } - - // Additional template param `Char_` is needed here because make_type always - // uses char. - template - MakeValue(const NamedArg& value) { - pointer = &value; - } - - template - static uint64_t - type(const NamedArg&) { - return Arg::NAMED_ARG; - } -}; - -template -struct NamedArg : Arg { - BasicStringRef name; - - typedef internal::MakeValue> MakeValue; - - template - NamedArg(BasicStringRef argname, const T& value) - : Arg(MakeValue(value)), name(argname) { - type = static_cast(MakeValue::type(value)); - } -}; - -#define FMT_DISPATCH(call) static_cast(this)->call - -// An argument visitor. -// To use ArgVisitor define a subclass that implements some or all of the -// visit methods with the same signatures as the methods in ArgVisitor, -// for example, visit_int(int). -// Specify the subclass name as the Impl template parameter. Then calling -// ArgVisitor::visit for some argument will dispatch to a visit method -// specific to the argument type. For example, if the argument type is -// double then visit_double(double) method of a subclass will be called. -// If the subclass doesn't contain a method with this signature, then -// a corresponding method of ArgVisitor will be called. -// -// Example: -// class MyArgVisitor : public ArgVisitor { -// public: -// void visit_int(int value) { print("{}", value); } -// void visit_double(double value) { print("{}", value ); } -// }; -// -// ArgVisitor uses the curiously recurring template pattern: -// http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern -template -class ArgVisitor { -public: - void - report_unhandled_arg() {} - - Result - visit_unhandled_arg() { - FMT_DISPATCH(report_unhandled_arg()); - return Result(); - } - - Result - visit_int(int value) { - return FMT_DISPATCH(visit_any_int(value)); - } - Result - visit_long_long(LongLong value) { - return FMT_DISPATCH(visit_any_int(value)); - } - Result - visit_uint(unsigned value) { - return FMT_DISPATCH(visit_any_int(value)); - } - Result - visit_ulong_long(ULongLong value) { - return FMT_DISPATCH(visit_any_int(value)); - } - Result - visit_bool(bool value) { - return FMT_DISPATCH(visit_any_int(value)); - } - Result - visit_char(int value) { - return FMT_DISPATCH(visit_any_int(value)); - } - template - Result visit_any_int(T) { - return FMT_DISPATCH(visit_unhandled_arg()); - } - - Result - visit_double(double value) { - return FMT_DISPATCH(visit_any_double(value)); - } - Result - visit_long_double(long double value) { - return FMT_DISPATCH(visit_any_double(value)); - } - template - Result visit_any_double(T) { - return FMT_DISPATCH(visit_unhandled_arg()); - } - - Result - visit_cstring(const char*) { - return FMT_DISPATCH(visit_unhandled_arg()); - } - Result - visit_string(Arg::StringValue) { - return FMT_DISPATCH(visit_unhandled_arg()); - } - Result visit_wstring(Arg::StringValue) { return FMT_DISPATCH(visit_unhandled_arg()); } - Result - visit_pointer(const void*) { - return FMT_DISPATCH(visit_unhandled_arg()); - } - Result visit_custom(Arg::CustomValue) { return FMT_DISPATCH(visit_unhandled_arg()); } - - Result - visit(const Arg& arg) { - switch (arg.type) { - default: FMT_ASSERT(false, "invalid argument type"); return Result(); - case Arg::INT: return FMT_DISPATCH(visit_int(arg.int_value)); - case Arg::UINT: return FMT_DISPATCH(visit_uint(arg.uint_value)); - case Arg::LONG_LONG: return FMT_DISPATCH(visit_long_long(arg.long_long_value)); - case Arg::ULONG_LONG: return FMT_DISPATCH(visit_ulong_long(arg.ulong_long_value)); - case Arg::BOOL: return FMT_DISPATCH(visit_bool(arg.int_value != 0)); - case Arg::CHAR: return FMT_DISPATCH(visit_char(arg.int_value)); - case Arg::DOUBLE: return FMT_DISPATCH(visit_double(arg.double_value)); - case Arg::LONG_DOUBLE: return FMT_DISPATCH(visit_long_double(arg.long_double_value)); - case Arg::CSTRING: return FMT_DISPATCH(visit_cstring(arg.string.value)); - case Arg::STRING: return FMT_DISPATCH(visit_string(arg.string)); - case Arg::WSTRING: return FMT_DISPATCH(visit_wstring(arg.wstring)); - case Arg::POINTER: return FMT_DISPATCH(visit_pointer(arg.pointer)); - case Arg::CUSTOM: return FMT_DISPATCH(visit_custom(arg.custom)); - } - } -}; - -class RuntimeError : public std::runtime_error { -protected: - RuntimeError() : std::runtime_error("") {} -}; - -template -class PrintfArgFormatter; - -template -class ArgMap; -} // namespace internal - -/** An argument list. */ -class ArgList { -private: - // To reduce compiled code size per formatting function call, types of first - // MAX_PACKED_ARGS arguments are passed in the types_ field. - uint64_t types_; - union { - // If the number of arguments is less than MAX_PACKED_ARGS, the argument - // values are stored in values_, otherwise they are stored in args_. - // This is done to reduce compiled code size as storing larger objects - // may require more code (at least on x86-64) even if the same amount of - // data is actually copied to stack. It saves ~10% on the bloat test. - const internal::Value* values_; - const internal::Arg* args_; - }; - - internal::Arg::Type - type(unsigned index) const { - unsigned shift = index * 4; - uint64_t mask = 0xf; - return static_cast((types_ & (mask << shift)) >> shift); - } - - template - friend class internal::ArgMap; - -public: - // Maximum number of arguments with packed types. - enum { MAX_PACKED_ARGS = 16 }; - - ArgList() : types_(0) {} - - ArgList(ULongLong types, const internal::Value* values) : types_(types), values_(values) {} - ArgList(ULongLong types, const internal::Arg* args) : types_(types), args_(args) {} - - /** Returns the argument at specified index. */ - internal::Arg operator[](unsigned index) const { - using internal::Arg; - Arg arg; - bool use_values = type(MAX_PACKED_ARGS - 1) == Arg::NONE; - if (index < MAX_PACKED_ARGS) { - Arg::Type arg_type = type(index); - internal::Value& val = arg; - if (arg_type != Arg::NONE) val = use_values ? values_[index] : args_[index]; - arg.type = arg_type; - return arg; - } - if (use_values) { - // The index is greater than the number of arguments that can be stored - // in values, so return a "none" argument. - arg.type = Arg::NONE; - return arg; - } - for (unsigned i = MAX_PACKED_ARGS; i <= index; ++i) { - if (args_[i].type == Arg::NONE) return args_[i]; - } - return args_[index]; - } -}; - -enum Alignment { ALIGN_DEFAULT, ALIGN_LEFT, ALIGN_RIGHT, ALIGN_CENTER, ALIGN_NUMERIC }; - -// Flags. -enum { - SIGN_FLAG = 1, - PLUS_FLAG = 2, - MINUS_FLAG = 4, - HASH_FLAG = 8, - CHAR_FLAG = 0x10 // Argument has char type - used in error reporting. -}; - -// An empty format specifier. -struct EmptySpec {}; - -// A type specifier. -template -struct TypeSpec : EmptySpec { - Alignment - align() const { - return ALIGN_DEFAULT; - } - unsigned - width() const { - return 0; - } - int - precision() const { - return -1; - } - bool - flag(unsigned) const { - return false; - } - char - type() const { - return TYPE; - } - char - fill() const { - return ' '; - } -}; - -// A width specifier. -struct WidthSpec { - unsigned width_; - // Fill is always wchar_t and cast to char if necessary to avoid having - // two specialization of WidthSpec and its subclasses. - wchar_t fill_; - - WidthSpec(unsigned width, wchar_t fill) : width_(width), fill_(fill) {} - - unsigned - width() const { - return width_; - } - wchar_t - fill() const { - return fill_; - } -}; - -// An alignment specifier. -struct AlignSpec : WidthSpec { - Alignment align_; - - AlignSpec(unsigned width, wchar_t fill, Alignment align = ALIGN_DEFAULT) - : WidthSpec(width, fill), align_(align) {} - - Alignment - align() const { - return align_; - } - - int - precision() const { - return -1; - } -}; - -// An alignment and type specifier. -template -struct AlignTypeSpec : AlignSpec { - AlignTypeSpec(unsigned width, wchar_t fill) : AlignSpec(width, fill) {} - - bool - flag(unsigned) const { - return false; - } - char - type() const { - return TYPE; - } -}; - -// A full format specifier. -struct FormatSpec : AlignSpec { - unsigned flags_; - int precision_; - char type_; - - FormatSpec(unsigned width = 0, char type = 0, wchar_t fill = ' ') - : AlignSpec(width, fill), flags_(0), precision_(-1), type_(type) {} - - bool - flag(unsigned f) const { - return (flags_ & f) != 0; - } - int - precision() const { - return precision_; - } - char - type() const { - return type_; - } -}; - -// An integer format specifier. -template , typename Char = char> -class IntFormatSpec : public SpecT { -private: - T value_; - -public: - IntFormatSpec(T val, const SpecT& spec = SpecT()) : SpecT(spec), value_(val) {} - - T - value() const { - return value_; - } -}; - -// A string format specifier. -template -class StrFormatSpec : public AlignSpec { -private: - const Char* str_; - -public: - template - StrFormatSpec(const Char* str, unsigned width, FillChar fill) - : AlignSpec(width, fill), str_(str) { - internal::CharTraits::convert(FillChar()); - } - - const Char* - str() const { - return str_; - } -}; - -/** -Returns an integer format specifier to format the value in base 2. -*/ -IntFormatSpec> bin(int value); - -/** -Returns an integer format specifier to format the value in base 8. -*/ -IntFormatSpec> oct(int value); - -/** -Returns an integer format specifier to format the value in base 16 using -lower-case letters for the digits above 9. -*/ -IntFormatSpec> hex(int value); - -/** -Returns an integer formatter format specifier to format in base 16 using -upper-case letters for the digits above 9. -*/ -IntFormatSpec> hexu(int value); - -/** -\rst -Returns an integer format specifier to pad the formatted argument with the -fill character to the specified width using the default (right) numeric -alignment. - -**Example**:: - -MemoryWriter out; -out << pad(hex(0xcafe), 8, '0'); -// out.str() == "0000cafe" - -\endrst -*/ -template -IntFormatSpec, Char> pad(int value, unsigned width, Char fill = ' '); - -#define FMT_DEFINE_INT_FORMATTERS(TYPE) \ - inline IntFormatSpec> bin(TYPE value) { \ - return IntFormatSpec>(value, TypeSpec<'b'>()); \ - } \ - \ - inline IntFormatSpec> oct(TYPE value) { \ - return IntFormatSpec>(value, TypeSpec<'o'>()); \ - } \ - \ - inline IntFormatSpec> hex(TYPE value) { \ - return IntFormatSpec>(value, TypeSpec<'x'>()); \ - } \ - \ - inline IntFormatSpec> hexu(TYPE value) { \ - return IntFormatSpec>(value, TypeSpec<'X'>()); \ - } \ - \ - template \ - inline IntFormatSpec> pad( \ - IntFormatSpec> f, unsigned width) { \ - return IntFormatSpec>( \ - f.value(), AlignTypeSpec(width, ' ')); \ - } \ - \ - /* For compatibility with older compilers we provide two overloads for pad, */ \ - /* one that takes a fill character and one that doesn't. In the future this */ \ - /* can be replaced with one overload making the template argument Char */ \ - /* default to char (C++11). */ \ - template \ - inline IntFormatSpec, Char> pad( \ - IntFormatSpec, Char> f, unsigned width, Char fill) { \ - return IntFormatSpec, Char>( \ - f.value(), AlignTypeSpec(width, fill)); \ - } \ - \ - inline IntFormatSpec> pad(TYPE value, unsigned width) { \ - return IntFormatSpec>(value, AlignTypeSpec<0>(width, ' ')); \ - } \ - \ - template \ - inline IntFormatSpec, Char> pad( \ - TYPE value, unsigned width, Char fill) { \ - return IntFormatSpec, Char>(value, AlignTypeSpec<0>(width, fill)); \ - } - -FMT_DEFINE_INT_FORMATTERS(int) -FMT_DEFINE_INT_FORMATTERS(long) -FMT_DEFINE_INT_FORMATTERS(unsigned) -FMT_DEFINE_INT_FORMATTERS(unsigned long) -FMT_DEFINE_INT_FORMATTERS(LongLong) -FMT_DEFINE_INT_FORMATTERS(ULongLong) - -/** -\rst -Returns a string formatter that pads the formatted argument with the fill -character to the specified width using the default (left) string alignment. - -**Example**:: - -std::string s = str(MemoryWriter() << pad("abc", 8)); -// s == "abc " - -\endrst -*/ -template -inline StrFormatSpec -pad(const Char* str, unsigned width, Char fill = ' ') { - return StrFormatSpec(str, width, fill); -} - -inline StrFormatSpec -pad(const wchar_t* str, unsigned width, char fill = ' ') { - return StrFormatSpec(str, width, fill); -} - -namespace internal { - -template -class ArgMap { -private: - typedef std::map, internal::Arg> MapType; - typedef typename MapType::value_type Pair; - - MapType map_; - -public: - FMT_API void init(const ArgList& args); - - const internal::Arg* - find(const fmt::BasicStringRef& name) const { - typename MapType::const_iterator it = map_.find(name); - return it != map_.end() ? &it->second : 0; - } -}; - -template -class ArgFormatterBase : public ArgVisitor { -private: - BasicWriter& writer_; - FormatSpec& spec_; - - FMT_DISALLOW_COPY_AND_ASSIGN(ArgFormatterBase); - - void - write_pointer(const void* p) { - spec_.flags_ = HASH_FLAG; - spec_.type_ = 'x'; - writer_.write_int(reinterpret_cast(p), spec_); - } - -protected: - BasicWriter& - writer() { - return writer_; - } - FormatSpec& - spec() { - return spec_; - } - - void - write(bool value) { - const char* str_value = value ? "true" : "false"; - Arg::StringValue str = { str_value, std::strlen(str_value) }; - writer_.write_str(str, spec_); - } - - void - write(const char* value) { - Arg::StringValue str = { value, value != 0 ? std::strlen(value) : 0 }; - writer_.write_str(str, spec_); - } - -public: - ArgFormatterBase(BasicWriter& w, FormatSpec& s) : writer_(w), spec_(s) {} - - template - void - visit_any_int(T value) { - writer_.write_int(value, spec_); - } - - template - void - visit_any_double(T value) { - writer_.write_double(value, spec_); - } - - void - visit_bool(bool value) { - if (spec_.type_) return visit_any_int(value); - write(value); - } - - void - visit_char(int value) { - if (spec_.type_ && spec_.type_ != 'c') { - spec_.flags_ |= CHAR_FLAG; - writer_.write_int(value, spec_); - return; - } - if (spec_.align_ == ALIGN_NUMERIC || spec_.flags_ != 0) - FMT_THROW(FormatError("invalid format specifier for char")); - typedef typename BasicWriter::CharPtr CharPtr; - Char fill = internal::CharTraits::cast(spec_.fill()); - CharPtr out = CharPtr(); - const unsigned CHAR_WIDTH = 1; - if (spec_.width_ > CHAR_WIDTH) { - out = writer_.grow_buffer(spec_.width_); - if (spec_.align_ == ALIGN_RIGHT) { - std::uninitialized_fill_n(out, spec_.width_ - CHAR_WIDTH, fill); - out += spec_.width_ - CHAR_WIDTH; - } else if (spec_.align_ == ALIGN_CENTER) { - out = writer_.fill_padding(out, spec_.width_, internal::check(CHAR_WIDTH), fill); - } else { - std::uninitialized_fill_n(out + CHAR_WIDTH, spec_.width_ - CHAR_WIDTH, fill); - } - } else { - out = writer_.grow_buffer(CHAR_WIDTH); - } - *out = internal::CharTraits::cast(value); - } - - void - visit_cstring(const char* value) { - if (spec_.type_ == 'p') return write_pointer(value); - write(value); - } - - void - visit_string(Arg::StringValue value) { - writer_.write_str(value, spec_); - } - - using ArgVisitor::visit_wstring; - - void - visit_wstring(Arg::StringValue value) { - writer_.write_str(value, spec_); - } - - void - visit_pointer(const void* value) { - if (spec_.type_ && spec_.type_ != 'p') report_unknown_type(spec_.type_, "pointer"); - write_pointer(value); - } -}; - -// An argument formatter. -template -class BasicArgFormatter : public ArgFormatterBase, Char> { -private: - BasicFormatter& formatter_; - const Char* format_; - -public: - BasicArgFormatter(BasicFormatter& f, FormatSpec& s, const Char* fmt) - : ArgFormatterBase, Char>(f.writer(), s), formatter_(f), format_(fmt) {} - - void - visit_custom(Arg::CustomValue c) { - c.format(&formatter_, c.value, &format_); - } -}; - -class FormatterBase { -private: - ArgList args_; - int next_arg_index_; - - // Returns the argument with specified index. - FMT_API Arg do_get_arg(unsigned arg_index, const char*& error); - -protected: - const ArgList& - args() const { - return args_; - } - - explicit FormatterBase(const ArgList& args) { - args_ = args; - next_arg_index_ = 0; - } - - // Returns the next argument. - Arg - next_arg(const char*& error) { - if (next_arg_index_ >= 0) return do_get_arg(next_arg_index_++, error); - error = "cannot switch from manual to automatic argument indexing"; - return Arg(); - } - - // Checks if manual indexing is used and returns the argument with - // specified index. - Arg - get_arg(unsigned arg_index, const char*& error) { - return check_no_auto_index(error) ? do_get_arg(arg_index, error) : Arg(); - } - - bool - check_no_auto_index(const char*& error) { - if (next_arg_index_ > 0) { - error = "cannot switch from automatic to manual argument indexing"; - return false; - } - next_arg_index_ = -1; - return true; - } - - template - void - write(BasicWriter& w, const Char* start, const Char* end) { - if (start != end) w << BasicStringRef(start, end - start); - } -}; - -// A printf formatter. -template -class PrintfFormatter : private FormatterBase { -private: - void parse_flags(FormatSpec& spec, const Char*& s); - - // Returns the argument with specified index or, if arg_index is equal - // to the maximum unsigned value, the next argument. - Arg get_arg(const Char* s, unsigned arg_index = (std::numeric_limits::max)()); - - // Parses argument index, flags and width and returns the argument index. - unsigned parse_header(const Char*& s, FormatSpec& spec); - -public: - explicit PrintfFormatter(const ArgList& args) : FormatterBase(args) {} - FMT_API void format(BasicWriter& writer, BasicCStringRef format_str); -}; -} // namespace internal - -// A formatter. -template -class BasicFormatter : private internal::FormatterBase { -public: - typedef CharType Char; - -private: - BasicWriter& writer_; - internal::ArgMap map_; - - FMT_DISALLOW_COPY_AND_ASSIGN(BasicFormatter); - - using internal::FormatterBase::get_arg; - - // Checks if manual indexing is used and returns the argument with - // specified name. - internal::Arg get_arg(BasicStringRef arg_name, const char*& error); - - // Parses argument index and returns corresponding argument. - internal::Arg parse_arg_index(const Char*& s); - - // Parses argument name and returns corresponding argument. - internal::Arg parse_arg_name(const Char*& s); - -public: - BasicFormatter(const ArgList& args, BasicWriter& w) - : internal::FormatterBase(args), writer_(w) {} - - BasicWriter& - writer() { - return writer_; - } - - void format(BasicCStringRef format_str); - - const Char* format(const Char*& format_str, const internal::Arg& arg); -}; - -// Generates a comma-separated list with results of applying f to -// numbers 0..n-1. -#define FMT_GEN(n, f) FMT_GEN##n(f) -#define FMT_GEN1(f) f(0) -#define FMT_GEN2(f) FMT_GEN1(f), f(1) -#define FMT_GEN3(f) FMT_GEN2(f), f(2) -#define FMT_GEN4(f) FMT_GEN3(f), f(3) -#define FMT_GEN5(f) FMT_GEN4(f), f(4) -#define FMT_GEN6(f) FMT_GEN5(f), f(5) -#define FMT_GEN7(f) FMT_GEN6(f), f(6) -#define FMT_GEN8(f) FMT_GEN7(f), f(7) -#define FMT_GEN9(f) FMT_GEN8(f), f(8) -#define FMT_GEN10(f) FMT_GEN9(f), f(9) -#define FMT_GEN11(f) FMT_GEN10(f), f(10) -#define FMT_GEN12(f) FMT_GEN11(f), f(11) -#define FMT_GEN13(f) FMT_GEN12(f), f(12) -#define FMT_GEN14(f) FMT_GEN13(f), f(13) -#define FMT_GEN15(f) FMT_GEN14(f), f(14) - -namespace internal { -inline uint64_t -make_type() { - return 0; -} - -template -inline uint64_t -make_type(const T& arg) { - return MakeValue>::type(arg); -} - -template -struct ArgArray { - // Computes the argument array size by adding 1 to N, which is the number of - // arguments, if N is zero, because array of zero size is invalid, or if N - // is greater than ArgList::MAX_PACKED_ARGS to accommodate for an extra - // argument that marks the end of the list. - enum { SIZE = N + (N == 0 || N >= ArgList::MAX_PACKED_ARGS ? 1 : 0) }; - - typedef typename Conditional<(N < ArgList::MAX_PACKED_ARGS), Value, Arg>::type Type[SIZE]; -}; - -#if FMT_USE_VARIADIC_TEMPLATES -template -inline uint64_t -make_type(const Arg& first, const Args&... tail) { - return make_type(first) | (make_type(tail...) << 4); -} - -inline void -do_set_types(Arg*) {} - -template -inline void -do_set_types(Arg* args, const T& arg, const Args&... tail) { - args->type = static_cast(MakeValue>::type(arg)); - do_set_types(args + 1, tail...); -} - -template -inline void -set_types(Arg* array, const Args&... args) { - if (check(sizeof...(Args) > ArgList::MAX_PACKED_ARGS)) do_set_types(array, args...); - array[sizeof...(Args)].type = Arg::NONE; -} - -template -inline void -set_types(Value*, const Args&...) { - // Do nothing as types are passed separately from values. -} - -template -inline void -store_args(Value*) {} - -template -inline void -store_args(Arg* args, const T& arg, const Args&... tail) { - // Assign only the Value subobject of Arg and don't overwrite type (if any) - // that is assigned by set_types. - Value& value = *args; - value = MakeValue(arg); - store_args(args + 1, tail...); -} - -template -ArgList -make_arg_list(typename ArgArray::Type array, const Args&... args) { - if (check(sizeof...(Args) >= ArgList::MAX_PACKED_ARGS)) set_types(array, args...); - store_args(array, args...); - return ArgList(make_type(args...), array); -} -#else - -struct ArgType { - uint64_t type; - - ArgType() : type(0) {} - - template - ArgType(const T& arg) - : type(make_type(arg)) {} -}; - -#define FMT_ARG_TYPE_DEFAULT(n) ArgType t##n = ArgType() - -inline uint64_t make_type(FMT_GEN15(FMT_ARG_TYPE_DEFAULT)) { - return t0.type | (t1.type << 4) | (t2.type << 8) | (t3.type << 12) | (t4.type << 16) | - (t5.type << 20) | (t6.type << 24) | (t7.type << 28) | (t8.type << 32) | (t9.type << 36) | - (t10.type << 40) | (t11.type << 44) | (t12.type << 48) | (t13.type << 52) | - (t14.type << 56); -} -#endif - -template -class FormatBuf : public std::basic_streambuf { -private: - typedef typename std::basic_streambuf::int_type int_type; - typedef typename std::basic_streambuf::traits_type traits_type; - - Buffer& buffer_; - Char* start_; - -public: - FormatBuf(Buffer& buffer) : buffer_(buffer), start_(&buffer[0]) { - this->setp(start_, start_ + buffer_.capacity()); - } - - int_type - overflow(int_type ch = traits_type::eof()) { - if (!traits_type::eq_int_type(ch, traits_type::eof())) { - size_t size = this->pptr() - start_; - buffer_.resize(size); - buffer_.reserve(size * 2); - - start_ = &buffer_[0]; - start_[size] = traits_type::to_char_type(ch); - this->setp(start_ + size + 1, start_ + size * 2); - } - return ch; - } - - size_t - size() const { - return this->pptr() - start_; - } -}; -} // namespace internal - -#define FMT_MAKE_TEMPLATE_ARG(n) typename T##n -#define FMT_MAKE_ARG_TYPE(n) T##n -#define FMT_MAKE_ARG(n) const T##n& v##n -#define FMT_ASSIGN_char(n) arr[n] = fmt::internal::MakeValue>(v##n) -#define FMT_ASSIGN_wchar_t(n) arr[n] = fmt::internal::MakeValue>(v##n) - -#if FMT_USE_VARIADIC_TEMPLATES -// Defines a variadic function returning void. -#define FMT_VARIADIC_VOID(func, arg_type) \ - template \ - void func(arg_type arg0, const Args&... args) { \ - typename fmt::internal::ArgArray::Type array; \ - func(arg0, fmt::internal::make_arg_list>(array, args...)); \ - } - -// Defines a variadic constructor. -#define FMT_VARIADIC_CTOR(ctor, func, arg0_type, arg1_type) \ - template \ - ctor(arg0_type arg0, arg1_type arg1, const Args&... args) { \ - typename fmt::internal::ArgArray::Type array; \ - func(arg0, arg1, fmt::internal::make_arg_list>(array, args...)); \ - } - -#else - -#define FMT_MAKE_REF(n) fmt::internal::MakeValue>(v##n) -#define FMT_MAKE_REF2(n) v##n - -// Defines a wrapper for a function taking one argument of type arg_type -// and n additional arguments of arbitrary types. -#define FMT_WRAP1(func, arg_type, n) \ - template \ - inline void func(arg_type arg1, FMT_GEN(n, FMT_MAKE_ARG)) { \ - const fmt::internal::ArgArray::Type array = { FMT_GEN(n, FMT_MAKE_REF) }; \ - func(arg1, fmt::ArgList(fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), array)); \ - } - -// Emulates a variadic function returning void on a pre-C++11 compiler. -#define FMT_VARIADIC_VOID(func, arg_type) \ - inline void func(arg_type arg) { func(arg, fmt::ArgList()); } \ - FMT_WRAP1(func, arg_type, 1) \ - FMT_WRAP1(func, arg_type, 2) FMT_WRAP1(func, arg_type, 3) FMT_WRAP1(func, arg_type, 4) \ - FMT_WRAP1(func, arg_type, 5) FMT_WRAP1(func, arg_type, 6) FMT_WRAP1(func, arg_type, 7) \ - FMT_WRAP1(func, arg_type, 8) FMT_WRAP1(func, arg_type, 9) \ - FMT_WRAP1(func, arg_type, 10) - -#define FMT_CTOR(ctor, func, arg0_type, arg1_type, n) \ - template \ - ctor(arg0_type arg0, arg1_type arg1, FMT_GEN(n, FMT_MAKE_ARG)) { \ - const fmt::internal::ArgArray::Type array = { FMT_GEN(n, FMT_MAKE_REF) }; \ - func( \ - arg0, arg1, fmt::ArgList(fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), array)); \ - } - -// Emulates a variadic constructor on a pre-C++11 compiler. -#define FMT_VARIADIC_CTOR(ctor, func, arg0_type, arg1_type) \ - FMT_CTOR(ctor, func, arg0_type, arg1_type, 1) \ - FMT_CTOR(ctor, func, arg0_type, arg1_type, 2) \ - FMT_CTOR(ctor, func, arg0_type, arg1_type, 3) \ - FMT_CTOR(ctor, func, arg0_type, arg1_type, 4) \ - FMT_CTOR(ctor, func, arg0_type, arg1_type, 5) \ - FMT_CTOR(ctor, func, arg0_type, arg1_type, 6) \ - FMT_CTOR(ctor, func, arg0_type, arg1_type, 7) \ - FMT_CTOR(ctor, func, arg0_type, arg1_type, 8) \ - FMT_CTOR(ctor, func, arg0_type, arg1_type, 9) \ - FMT_CTOR(ctor, func, arg0_type, arg1_type, 10) -#endif - -// Generates a comma-separated list with results of applying f to pairs -// (argument, index). -#define FMT_FOR_EACH1(f, x0) f(x0, 0) -#define FMT_FOR_EACH2(f, x0, x1) FMT_FOR_EACH1(f, x0), f(x1, 1) -#define FMT_FOR_EACH3(f, x0, x1, x2) FMT_FOR_EACH2(f, x0, x1), f(x2, 2) -#define FMT_FOR_EACH4(f, x0, x1, x2, x3) FMT_FOR_EACH3(f, x0, x1, x2), f(x3, 3) -#define FMT_FOR_EACH5(f, x0, x1, x2, x3, x4) FMT_FOR_EACH4(f, x0, x1, x2, x3), f(x4, 4) -#define FMT_FOR_EACH6(f, x0, x1, x2, x3, x4, x5) FMT_FOR_EACH5(f, x0, x1, x2, x3, x4), f(x5, 5) -#define FMT_FOR_EACH7(f, x0, x1, x2, x3, x4, x5, x6) \ - FMT_FOR_EACH6(f, x0, x1, x2, x3, x4, x5), f(x6, 6) -#define FMT_FOR_EACH8(f, x0, x1, x2, x3, x4, x5, x6, x7) \ - FMT_FOR_EACH7(f, x0, x1, x2, x3, x4, x5, x6), f(x7, 7) -#define FMT_FOR_EACH9(f, x0, x1, x2, x3, x4, x5, x6, x7, x8) \ - FMT_FOR_EACH8(f, x0, x1, x2, x3, x4, x5, x6, x7), f(x8, 8) -#define FMT_FOR_EACH10(f, x0, x1, x2, x3, x4, x5, x6, x7, x8, x9) \ - FMT_FOR_EACH9(f, x0, x1, x2, x3, x4, x5, x6, x7, x8), f(x9, 9) - -/** -An error returned by an operating system or a language runtime, -for example a file opening error. -*/ -class SystemError : public internal::RuntimeError { -private: - void init(int err_code, CStringRef format_str, ArgList args); - -protected: - int error_code_; - - typedef char Char; // For FMT_VARIADIC_CTOR. - - SystemError() {} - -public: - /** - \rst - Constructs a :class:`fmt::SystemError` object with the description - of the form - - .. parsed-literal:: - **: ** - - where ** is the formatted message and ** is - the system message corresponding to the error code. - *error_code* is a system error code as given by ``errno``. - If *error_code* is not a valid error code such as -1, the system message - may look like "Unknown error -1" and is platform-dependent. - - **Example**:: - - // This throws a SystemError with the description - // cannot open file 'madeup': No such file or directory - // or similar (system message may vary). - const char *filename = "madeup"; - std::FILE *file = std::fopen(filename, "r"); - if (!file) - throw fmt::SystemError(errno, "cannot open file '{}'", filename); - \endrst - */ - SystemError(int error_code, CStringRef message) { init(error_code, message, ArgList()); } - FMT_VARIADIC_CTOR(SystemError, init, int, CStringRef) - - int - error_code() const { - return error_code_; - } -}; - -/** -\rst -This template provides operations for formatting and writing data into -a character stream. The output is stored in a buffer provided by a subclass -such as :class:`fmt::BasicMemoryWriter`. - -You can use one of the following typedefs for common character types: - -+---------+----------------------+ -| Type | Definition | -+=========+======================+ -| Writer | BasicWriter | -+---------+----------------------+ -| WWriter | BasicWriter | -+---------+----------------------+ - -\endrst -*/ -template -class BasicWriter { -private: - // Output buffer. - Buffer& buffer_; - - FMT_DISALLOW_COPY_AND_ASSIGN(BasicWriter); - - typedef typename internal::CharTraits::CharPtr CharPtr; - -#if FMT_SECURE_SCL - // Returns pointer value. - static Char* - get(CharPtr p) { - return p.base(); - } -#else - static Char* - get(Char* p) { - return p; - } -#endif - - // Fills the padding around the content and returns the pointer to the - // content area. - static CharPtr - fill_padding(CharPtr buffer, unsigned total_size, std::size_t content_size, wchar_t fill); - - // Grows the buffer by n characters and returns a pointer to the newly - // allocated area. - CharPtr - grow_buffer(std::size_t n) { - std::size_t size = buffer_.size(); - buffer_.resize(size + n); - return internal::make_ptr(&buffer_[size], n); - } - - // Writes an unsigned decimal integer. - template - Char* - write_unsigned_decimal(UInt value, unsigned prefix_size = 0) { - unsigned num_digits = internal::count_digits(value); - Char* ptr = get(grow_buffer(prefix_size + num_digits)); - internal::format_decimal(ptr + prefix_size, value, num_digits); - return ptr; - } - - // Writes a decimal integer. - template - void - write_decimal(Int value) { - typename internal::IntTraits::MainType abs_value = value; - if (internal::is_negative(value)) { - abs_value = 0 - abs_value; - *write_unsigned_decimal(abs_value, 1) = '-'; - } else { - write_unsigned_decimal(abs_value, 0); - } - } - - // Prepare a buffer for integer formatting. - CharPtr - prepare_int_buffer(unsigned num_digits, - const EmptySpec&, - const char* prefix, - unsigned prefix_size) { - unsigned size = prefix_size + num_digits; - CharPtr p = grow_buffer(size); - std::uninitialized_copy(prefix, prefix + prefix_size, p); - return p + size - 1; - } - - template - CharPtr prepare_int_buffer(unsigned num_digits, - const Spec& spec, - const char* prefix, - unsigned prefix_size); - - // Formats an integer. - template - void write_int(T value, Spec spec); - - // Formats a floating-point number (double or long double). - template - void write_double(T value, const FormatSpec& spec); - - // Writes a formatted string. - template - CharPtr write_str(const StrChar* s, std::size_t size, const AlignSpec& spec); - - template - void write_str(const internal::Arg::StringValue& str, const FormatSpec& spec); - - // This following methods are private to disallow writing wide characters - // and strings to a char stream. If you want to print a wide string as a - // pointer as std::ostream does, cast it to const void*. - // Do not implement! - void operator<<(typename internal::WCharHelper::Unsupported); - void operator<<(typename internal::WCharHelper::Unsupported); - - // Appends floating-point length specifier to the format string. - // The second argument is only used for overload resolution. - void - append_float_length(Char*& format_ptr, long double) { - *format_ptr++ = 'L'; - } - - template - void - append_float_length(Char*&, T) {} - - template - friend class internal::ArgFormatterBase; - - friend class internal::PrintfArgFormatter; - -protected: - /** - Constructs a ``BasicWriter`` object. - */ - explicit BasicWriter(Buffer& b) : buffer_(b) {} - -public: - /** - \rst - Destroys a ``BasicWriter`` object. - \endrst - */ - virtual ~BasicWriter() {} - - /** - Returns the total number of characters written. - */ - std::size_t - size() const { - return buffer_.size(); - } - - /** - Returns a pointer to the output buffer content. No terminating null - character is appended. - */ - const Char* - data() const FMT_NOEXCEPT { - return &buffer_[0]; - } - - /** - Returns a pointer to the output buffer content with terminating null - character appended. - */ - const Char* - c_str() const { - std::size_t size = buffer_.size(); - buffer_.reserve(size + 1); - buffer_[size] = '\0'; - return &buffer_[0]; - } - - /** - \rst - Returns the content of the output buffer as an `std::string`. - \endrst - */ - std::basic_string - str() const { - return std::basic_string(&buffer_[0], buffer_.size()); - } - - /** - \rst - Writes formatted data. - - *args* is an argument list representing arbitrary arguments. - - **Example**:: - - MemoryWriter out; - out.write("Current point:\n"); - out.write("({:+f}, {:+f})", -3.14, 3.14); - - This will write the following output to the ``out`` object: - - .. code-block:: none - - Current point: - (-3.140000, +3.140000) - - The output can be accessed using :func:`data()`, :func:`c_str` or - :func:`str` methods. - - See also :ref:`syntax`. - \endrst - */ - void - write(BasicCStringRef format, ArgList args) { - BasicFormatter(args, *this).format(format); - } - FMT_VARIADIC_VOID(write, BasicCStringRef) - - BasicWriter& operator<<(int value) { - write_decimal(value); - return *this; - } - BasicWriter& operator<<(unsigned value) { return *this << IntFormatSpec(value); } - BasicWriter& operator<<(long value) { - write_decimal(value); - return *this; - } - BasicWriter& operator<<(unsigned long value) { - return *this << IntFormatSpec(value); - } - BasicWriter& operator<<(LongLong value) { - write_decimal(value); - return *this; - } - - /** - \rst - Formats *value* and writes it to the stream. - \endrst - */ - BasicWriter& operator<<(ULongLong value) { return *this << IntFormatSpec(value); } - - BasicWriter& operator<<(double value) { - write_double(value, FormatSpec()); - return *this; - } - - /** - \rst - Formats *value* using the general format for floating-point numbers - (``'g'``) and writes it to the stream. - \endrst - */ - BasicWriter& operator<<(long double value) { - write_double(value, FormatSpec()); - return *this; - } - - /** - Writes a character to the stream. - */ - BasicWriter& operator<<(char value) { - buffer_.push_back(value); - return *this; - } - - BasicWriter& operator<<(typename internal::WCharHelper::Supported value) { - buffer_.push_back(value); - return *this; - } - - /** - \rst - Writes *value* to the stream. - \endrst - */ - BasicWriter& operator<<(fmt::BasicStringRef value) { - const Char* str = value.data(); - buffer_.append(str, str + value.size()); - return *this; - } - - BasicWriter& operator<<(typename internal::WCharHelper::Supported value) { - const char* str = value.data(); - buffer_.append(str, str + value.size()); - return *this; - } - - template - BasicWriter& operator<<(IntFormatSpec spec) { - internal::CharTraits::convert(FillChar()); - write_int(spec.value(), spec); - return *this; - } - - template - BasicWriter& operator<<(const StrFormatSpec& spec) { - const StrChar* s = spec.str(); - write_str(s, std::char_traits::length(s), spec); - return *this; - } - - void - clear() FMT_NOEXCEPT { - buffer_.clear(); - } -}; - -template -template -typename BasicWriter::CharPtr -BasicWriter::write_str(const StrChar* s, std::size_t size, const AlignSpec& spec) { - CharPtr out = CharPtr(); - if (spec.width() > size) { - out = grow_buffer(spec.width()); - Char fill = internal::CharTraits::cast(spec.fill()); - if (spec.align() == ALIGN_RIGHT) { - std::uninitialized_fill_n(out, spec.width() - size, fill); - out += spec.width() - size; - } else if (spec.align() == ALIGN_CENTER) { - out = fill_padding(out, spec.width(), size, fill); - } else { - std::uninitialized_fill_n(out + size, spec.width() - size, fill); - } - } else { - out = grow_buffer(size); - } - std::uninitialized_copy(s, s + size, out); - return out; -} - -template -template -void -BasicWriter::write_str(const internal::Arg::StringValue& s, const FormatSpec& spec) { - // Check if StrChar is convertible to Char. - internal::CharTraits::convert(StrChar()); - if (spec.type_ && spec.type_ != 's') internal::report_unknown_type(spec.type_, "string"); - const StrChar* str_value = s.value; - std::size_t str_size = s.size; - if (str_size == 0) { - if (!str_value) { - FMT_THROW(FormatError("string pointer is null")); - return; - } - } - std::size_t precision = spec.precision_; - if (spec.precision_ >= 0 && precision < str_size) str_size = spec.precision_; - write_str(str_value, str_size, spec); -} - -template -typename BasicWriter::CharPtr -BasicWriter::fill_padding(CharPtr buffer, - unsigned total_size, - std::size_t content_size, - wchar_t fill) { - std::size_t padding = total_size - content_size; - std::size_t left_padding = padding / 2; - Char fill_char = internal::CharTraits::cast(fill); - std::uninitialized_fill_n(buffer, left_padding, fill_char); - buffer += left_padding; - CharPtr content = buffer; - std::uninitialized_fill_n(buffer + content_size, padding - left_padding, fill_char); - return content; -} - -template -template -typename BasicWriter::CharPtr -BasicWriter::prepare_int_buffer(unsigned num_digits, - const Spec& spec, - const char* prefix, - unsigned prefix_size) { - unsigned width = spec.width(); - Alignment align = spec.align(); - Char fill = internal::CharTraits::cast(spec.fill()); - if (spec.precision() > static_cast(num_digits)) { - // Octal prefix '0' is counted as a digit, so ignore it if precision - // is specified. - if (prefix_size > 0 && prefix[prefix_size - 1] == '0') --prefix_size; - unsigned number_size = prefix_size + spec.precision(); - AlignSpec subspec(number_size, '0', ALIGN_NUMERIC); - if (number_size >= width) - return prepare_int_buffer(num_digits, subspec, prefix, prefix_size); - buffer_.reserve(width); - unsigned fill_size = width - number_size; - if (align != ALIGN_LEFT) { - CharPtr p = grow_buffer(fill_size); - std::uninitialized_fill(p, p + fill_size, fill); - } - CharPtr result = prepare_int_buffer(num_digits, subspec, prefix, prefix_size); - if (align == ALIGN_LEFT) { - CharPtr p = grow_buffer(fill_size); - std::uninitialized_fill(p, p + fill_size, fill); - } - return result; - } - unsigned size = prefix_size + num_digits; - if (width <= size) { - CharPtr p = grow_buffer(size); - std::uninitialized_copy(prefix, prefix + prefix_size, p); - return p + size - 1; - } - CharPtr p = grow_buffer(width); - CharPtr end = p + width; - if (align == ALIGN_LEFT) { - std::uninitialized_copy(prefix, prefix + prefix_size, p); - p += size; - std::uninitialized_fill(p, end, fill); - } else if (align == ALIGN_CENTER) { - p = fill_padding(p, width, size, fill); - std::uninitialized_copy(prefix, prefix + prefix_size, p); - p += size; - } else { - if (align == ALIGN_NUMERIC) { - if (prefix_size != 0) { - p = std::uninitialized_copy(prefix, prefix + prefix_size, p); - size -= prefix_size; - } - } else { - std::uninitialized_copy(prefix, prefix + prefix_size, end - size); - } - std::uninitialized_fill(p, end - size, fill); - p = end; - } - return p - 1; -} - -template -template -void -BasicWriter::write_int(T value, Spec spec) { - unsigned prefix_size = 0; - typedef typename internal::IntTraits::MainType UnsignedType; - UnsignedType abs_value = value; - char prefix[4] = ""; - if (internal::is_negative(value)) { - prefix[0] = '-'; - ++prefix_size; - abs_value = 0 - abs_value; - } else if (spec.flag(SIGN_FLAG)) { - prefix[0] = spec.flag(PLUS_FLAG) ? '+' : ' '; - ++prefix_size; - } - switch (spec.type()) { - case 0: - case 'd': { - unsigned num_digits = internal::count_digits(abs_value); - CharPtr p = prepare_int_buffer(num_digits, spec, prefix, prefix_size) + 1 - num_digits; - internal::format_decimal(get(p), abs_value, num_digits); - break; - } - case 'x': - case 'X': { - UnsignedType n = abs_value; - if (spec.flag(HASH_FLAG)) { - prefix[prefix_size++] = '0'; - prefix[prefix_size++] = spec.type(); - } - unsigned num_digits = 0; - do { ++num_digits; } while ((n >>= 4) != 0); - Char* p = get(prepare_int_buffer(num_digits, spec, prefix, prefix_size)); - n = abs_value; - const char* digits = spec.type() == 'x' ? "0123456789abcdef" : "0123456789ABCDEF"; - do { *p-- = digits[n & 0xf]; } while ((n >>= 4) != 0); - break; - } - case 'b': - case 'B': { - UnsignedType n = abs_value; - if (spec.flag(HASH_FLAG)) { - prefix[prefix_size++] = '0'; - prefix[prefix_size++] = spec.type(); - } - unsigned num_digits = 0; - do { ++num_digits; } while ((n >>= 1) != 0); - Char* p = get(prepare_int_buffer(num_digits, spec, prefix, prefix_size)); - n = abs_value; - do { *p-- = static_cast('0' + (n & 1)); } while ((n >>= 1) != 0); - break; - } - case 'o': { - UnsignedType n = abs_value; - if (spec.flag(HASH_FLAG)) prefix[prefix_size++] = '0'; - unsigned num_digits = 0; - do { ++num_digits; } while ((n >>= 3) != 0); - Char* p = get(prepare_int_buffer(num_digits, spec, prefix, prefix_size)); - n = abs_value; - do { *p-- = static_cast('0' + (n & 7)); } while ((n >>= 3) != 0); - break; - } - default: - internal::report_unknown_type(spec.type(), spec.flag(CHAR_FLAG) ? "char" : "integer"); - break; - } -} - -template -template -void -BasicWriter::write_double(T value, const FormatSpec& spec) { - // Check type. - char type = spec.type(); - bool upper = false; - switch (type) { - case 0: type = 'g'; break; - case 'e': - case 'f': - case 'g': - case 'a': break; - case 'F': -#ifdef _MSC_VER - // MSVC's printf doesn't support 'F'. - type = 'f'; -#endif - // Fall through. - case 'E': - case 'G': - case 'A': upper = true; break; - default: internal::report_unknown_type(type, "double"); break; - } - - char sign = 0; - // Use isnegative instead of value < 0 because the latter is always - // false for NaN. - if (internal::FPUtil::isnegative(static_cast(value))) { - sign = '-'; - value = -value; - } else if (spec.flag(SIGN_FLAG)) { - sign = spec.flag(PLUS_FLAG) ? '+' : ' '; - } - - if (internal::FPUtil::isnotanumber(value)) { - // Format NaN ourselves because sprintf's output is not consistent - // across platforms. - std::size_t nan_size = 4; - const char* nan = upper ? " NAN" : " nan"; - if (!sign) { - --nan_size; - ++nan; - } - CharPtr out = write_str(nan, nan_size, spec); - if (sign) *out = sign; - return; - } - - if (internal::FPUtil::isinfinity(value)) { - // Format infinity ourselves because sprintf's output is not consistent - // across platforms. - std::size_t inf_size = 4; - const char* inf = upper ? " INF" : " inf"; - if (!sign) { - --inf_size; - ++inf; - } - CharPtr out = write_str(inf, inf_size, spec); - if (sign) *out = sign; - return; - } - - std::size_t offset = buffer_.size(); - unsigned width = spec.width(); - if (sign) { - buffer_.reserve(buffer_.size() + (width > 1u ? width : 1u)); - if (width > 0) --width; - ++offset; - } - - // Build format string. - enum { MAX_FORMAT_SIZE = 10 }; // longest format: %#-*.*Lg - Char format[MAX_FORMAT_SIZE]; - Char* format_ptr = format; - *format_ptr++ = '%'; - unsigned width_for_sprintf = width; - if (spec.flag(HASH_FLAG)) *format_ptr++ = '#'; - if (spec.align() == ALIGN_CENTER) { - width_for_sprintf = 0; - } else { - if (spec.align() == ALIGN_LEFT) *format_ptr++ = '-'; - if (width != 0) *format_ptr++ = '*'; - } - if (spec.precision() >= 0) { - *format_ptr++ = '.'; - *format_ptr++ = '*'; - } - - append_float_length(format_ptr, value); - *format_ptr++ = type; - *format_ptr = '\0'; - - // Format using snprintf. - Char fill = internal::CharTraits::cast(spec.fill()); - for (;;) { - std::size_t buffer_size = buffer_.capacity() - offset; -#ifdef _MSC_VER - // MSVC's vsnprintf_s doesn't work with zero size, so reserve - // space for at least one extra character to make the size non-zero. - // Note that the buffer's capacity will increase by more than 1. - if (buffer_size == 0) { - buffer_.reserve(offset + 1); - buffer_size = buffer_.capacity() - offset; - } -#endif - Char* start = &buffer_[offset]; - int n = internal::CharTraits::format_float( - start, buffer_size, format, width_for_sprintf, spec.precision(), value); - if (n >= 0 && offset + n < buffer_.capacity()) { - if (sign) { - if ((spec.align() != ALIGN_RIGHT && spec.align() != ALIGN_DEFAULT) || - *start != ' ') { - *(start - 1) = sign; - sign = 0; - } else { - *(start - 1) = fill; - } - ++n; - } - if (spec.align() == ALIGN_CENTER && spec.width() > static_cast(n)) { - width = spec.width(); - CharPtr p = grow_buffer(width); - std::memmove(get(p) + (width - n) / 2, get(p), n * sizeof(Char)); - fill_padding(p, spec.width(), n, fill); - return; - } - if (spec.fill() != ' ' || sign) { - while (*start == ' ') *start++ = fill; - if (sign) *(start - 1) = sign; - } - grow_buffer(n); - return; - } - // If n is negative we ask to increase the capacity by at least 1, - // but as std::vector, the buffer grows exponentially. - buffer_.reserve(n >= 0 ? offset + n + 1 : buffer_.capacity() + 1); - } -} - -/** -\rst -This class template provides operations for formatting and writing data -into a character stream. The output is stored in a memory buffer that grows -dynamically. - -You can use one of the following typedefs for common character types -and the standard allocator: - -+---------------+-----------------------------------------------------+ -| Type | Definition | -+===============+=====================================================+ -| MemoryWriter | BasicMemoryWriter> | -+---------------+-----------------------------------------------------+ -| WMemoryWriter | BasicMemoryWriter> | -+---------------+-----------------------------------------------------+ - -**Example**:: - -MemoryWriter out; -out << "The answer is " << 42 << "\n"; -out.write("({:+f}, {:+f})", -3.14, 3.14); - -This will write the following output to the ``out`` object: - -.. code-block:: none - -The answer is 42 -(-3.140000, +3.140000) - -The output can be converted to an ``std::string`` with ``out.str()`` or -accessed as a C string with ``out.c_str()``. -\endrst -*/ -template > -class BasicMemoryWriter : public BasicWriter { -private: - internal::MemoryBuffer buffer_; - -public: - explicit BasicMemoryWriter(const Allocator& alloc = Allocator()) - : BasicWriter(buffer_), buffer_(alloc) {} - -#if FMT_USE_RVALUE_REFERENCES - /** - \rst - Constructs a :class:`fmt::BasicMemoryWriter` object moving the content - of the other object to it. - \endrst - */ - BasicMemoryWriter(BasicMemoryWriter&& other) - : BasicWriter(buffer_), buffer_(std::move(other.buffer_)) {} - - /** - \rst - Moves the content of the other ``BasicMemoryWriter`` object to this one. - \endrst - */ - BasicMemoryWriter& operator=(BasicMemoryWriter&& other) { - buffer_ = std::move(other.buffer_); - return *this; - } -#endif -}; - -typedef BasicMemoryWriter MemoryWriter; -typedef BasicMemoryWriter WMemoryWriter; - -/** -\rst -This class template provides operations for formatting and writing data -into a fixed-size array. For writing into a dynamically growing buffer -use :class:`fmt::BasicMemoryWriter`. - -Any write method will throw ``std::runtime_error`` if the output doesn't fit -into the array. - -You can use one of the following typedefs for common character types: - -+--------------+---------------------------+ -| Type | Definition | -+==============+===========================+ -| ArrayWriter | BasicArrayWriter | -+--------------+---------------------------+ -| WArrayWriter | BasicArrayWriter | -+--------------+---------------------------+ -\endrst -*/ -template -class BasicArrayWriter : public BasicWriter { -private: - internal::FixedBuffer buffer_; - -public: - /** - \rst - Constructs a :class:`fmt::BasicArrayWriter` object for *array* of the - given size. - \endrst - */ - BasicArrayWriter(Char* array, std::size_t size) - : BasicWriter(buffer_), buffer_(array, size) {} - - /** - \rst - Constructs a :class:`fmt::BasicArrayWriter` object for *array* of the - size known at compile time. - \endrst - */ - template - explicit BasicArrayWriter(Char(&array)[SIZE]) - : BasicWriter(buffer_), buffer_(array, SIZE) {} -}; - -typedef BasicArrayWriter ArrayWriter; -typedef BasicArrayWriter WArrayWriter; - -// Formats a value. -template -void -format(BasicFormatter& f, const Char*& format_str, const T& value) { - internal::MemoryBuffer buffer; - - internal::FormatBuf format_buf(buffer); - std::basic_ostream output(&format_buf); - output << value; - - BasicStringRef str(&buffer[0], format_buf.size()); - typedef internal::MakeValue> MakeValue; - internal::Arg arg = MakeValue(str); - arg.type = static_cast(MakeValue::type(str)); - format_str = f.format(format_str, arg); -} - -// Reports a system error without throwing an exception. -// Can be used to report errors from destructors. -FMT_API void report_system_error(int error_code, StringRef message) FMT_NOEXCEPT; - -#if FMT_USE_WINDOWS_H - -/** A Windows error. */ -class WindowsError : public SystemError { -private: - FMT_API void init(int error_code, CStringRef format_str, ArgList args); - -public: - /** - \rst - Constructs a :class:`fmt::WindowsError` object with the description - of the form - - .. parsed-literal:: - **: ** - - where ** is the formatted message and ** is the - system message corresponding to the error code. - *error_code* is a Windows error code as given by ``GetLastError``. - If *error_code* is not a valid error code such as -1, the system message - will look like "error -1". - - **Example**:: - - // This throws a WindowsError with the description - // cannot open file 'madeup': The system cannot find the file specified. - // or similar (system message may vary). - const char *filename = "madeup"; - LPOFSTRUCT of = LPOFSTRUCT(); - HFILE file = OpenFile(filename, &of, OF_READ); - if (file == HFILE_ERROR) { - throw fmt::WindowsError(GetLastError(), - "cannot open file '{}'", filename); - } - \endrst - */ - WindowsError(int error_code, CStringRef message) { init(error_code, message, ArgList()); } - FMT_VARIADIC_CTOR(WindowsError, init, int, CStringRef) -}; - -// Reports a Windows error without throwing an exception. -// Can be used to report errors from destructors. -FMT_API void report_windows_error(int error_code, StringRef message) FMT_NOEXCEPT; - -#endif - -enum Color { BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE }; - -/** -Formats a string and prints it to stdout using ANSI escape sequences -to specify color (experimental). -Example: -print_colored(fmt::RED, "Elapsed time: {0:.2f} seconds", 1.23); -*/ -FMT_API void print_colored(Color c, CStringRef format, ArgList args); - -/** -\rst -Formats arguments and returns the result as a string. - -**Example**:: - -std::string message = format("The answer is {}", 42); -\endrst -*/ -inline std::string -format(CStringRef format_str, ArgList args) { - MemoryWriter w; - w.write(format_str, args); - return w.str(); -} - -inline std::wstring -format(WCStringRef format_str, ArgList args) { - WMemoryWriter w; - w.write(format_str, args); - return w.str(); -} - -/** -\rst -Prints formatted data to the file *f*. - -**Example**:: - -print(stderr, "Don't {}!", "panic"); -\endrst -*/ -FMT_API void print(std::FILE* f, CStringRef format_str, ArgList args); - -/** -\rst -Prints formatted data to ``stdout``. - -**Example**:: - -print("Elapsed time: {0:.2f} seconds", 1.23); -\endrst -*/ -FMT_API void print(CStringRef format_str, ArgList args); - -template -void -printf(BasicWriter& w, BasicCStringRef format, ArgList args) { - internal::PrintfFormatter(args).format(w, format); -} - -/** -\rst -Formats arguments and returns the result as a string. - -**Example**:: - -std::string message = fmt::sprintf("The answer is %d", 42); -\endrst -*/ -inline std::string -sprintf(CStringRef format, ArgList args) { - MemoryWriter w; - printf(w, format, args); - return w.str(); -} - -inline std::wstring -sprintf(WCStringRef format, ArgList args) { - WMemoryWriter w; - printf(w, format, args); - return w.str(); -} - -/** -\rst -Prints formatted data to the file *f*. - -**Example**:: - -fmt::fprintf(stderr, "Don't %s!", "panic"); -\endrst -*/ -FMT_API int fprintf(std::FILE* f, CStringRef format, ArgList args); - -/** -\rst -Prints formatted data to ``stdout``. - -**Example**:: - -fmt::printf("Elapsed time: %.2f seconds", 1.23); -\endrst -*/ -inline int -printf(CStringRef format, ArgList args) { - return fprintf(stdout, format, args); -} - -/** -Fast integer formatter. -*/ -class FormatInt { -private: - // Buffer should be large enough to hold all digits (digits10 + 1), - // a sign and a null character. - enum { BUFFER_SIZE = std::numeric_limits::digits10 + 3 }; - mutable char buffer_[BUFFER_SIZE]; - char* str_; - - // Formats value in reverse and returns the number of digits. - char* - format_decimal(ULongLong value) { - char* buffer_end = buffer_ + BUFFER_SIZE - 1; - while (value >= 100) { - // Integer division is slow so do it for a group of two digits instead - // of for every digit. The idea comes from the talk by Alexandrescu - // "Three Optimization Tips for C++". See speed-test for a comparison. - unsigned index = static_cast((value % 100) * 2); - value /= 100; - *--buffer_end = internal::Data::DIGITS[index + 1]; - *--buffer_end = internal::Data::DIGITS[index]; - } - if (value < 10) { - *--buffer_end = static_cast('0' + value); - return buffer_end; - } - unsigned index = static_cast(value * 2); - *--buffer_end = internal::Data::DIGITS[index + 1]; - *--buffer_end = internal::Data::DIGITS[index]; - return buffer_end; - } - - void - FormatSigned(LongLong value) { - ULongLong abs_value = static_cast(value); - bool negative = value < 0; - if (negative) abs_value = 0 - abs_value; - str_ = format_decimal(abs_value); - if (negative) *--str_ = '-'; - } - -public: - explicit FormatInt(int value) { FormatSigned(value); } - explicit FormatInt(long value) { FormatSigned(value); } - explicit FormatInt(LongLong value) { FormatSigned(value); } - explicit FormatInt(unsigned value) : str_(format_decimal(value)) {} - explicit FormatInt(unsigned long value) : str_(format_decimal(value)) {} - explicit FormatInt(ULongLong value) : str_(format_decimal(value)) {} - - /** - Returns the number of characters written to the output buffer. - */ - std::size_t - size() const { - return buffer_ - str_ + BUFFER_SIZE - 1; - } - - /** - Returns a pointer to the output buffer content. No terminating null - character is appended. - */ - const char* - data() const { - return str_; - } - - /** - Returns a pointer to the output buffer content with terminating null - character appended. - */ - const char* - c_str() const { - buffer_[BUFFER_SIZE - 1] = '\0'; - return str_; - } - - /** - \rst - Returns the content of the output buffer as an ``std::string``. - \endrst - */ - std::string - str() const { - return std::string(str_, size()); - } -}; - -// Formats a decimal integer value writing into buffer and returns -// a pointer to the end of the formatted string. This function doesn't -// write a terminating null character. -template -inline void -format_decimal(char*& buffer, T value) { - typename internal::IntTraits::MainType abs_value = value; - if (internal::is_negative(value)) { - *buffer++ = '-'; - abs_value = 0 - abs_value; - } - if (abs_value < 100) { - if (abs_value < 10) { - *buffer++ = static_cast('0' + abs_value); - return; - } - unsigned index = static_cast(abs_value * 2); - *buffer++ = internal::Data::DIGITS[index]; - *buffer++ = internal::Data::DIGITS[index + 1]; - return; - } - unsigned num_digits = internal::count_digits(abs_value); - internal::format_decimal(buffer, abs_value, num_digits); - buffer += num_digits; -} - -/** -\rst -Returns a named argument for formatting functions. - -**Example**:: - -print("Elapsed time: {s:.2f} seconds", arg("s", 1.23)); - -\endrst -*/ -template -inline internal::NamedArg -arg(StringRef name, const T& arg) { - return internal::NamedArg(name, arg); -} - -template -inline internal::NamedArg -arg(WStringRef name, const T& arg) { - return internal::NamedArg(name, arg); -} - -// The following two functions are deleted intentionally to disable -// nested named arguments as in ``format("{}", arg("a", arg("b", 42)))``. -template -void arg(StringRef, const internal::NamedArg&) FMT_DELETED_OR_UNDEFINED; -template -void arg(WStringRef, const internal::NamedArg&) FMT_DELETED_OR_UNDEFINED; -} - -#if FMT_GCC_VERSION -// Use the system_header pragma to suppress warnings about variadic macros -// because suppressing -Wvariadic-macros with the diagnostic pragma doesn't -// work. It is used at the end because we want to suppress as little warnings -// as possible. -#pragma GCC system_header -#endif - -// This is used to work around VC++ bugs in handling variadic macros. -#define FMT_EXPAND(args) args - -// Returns the number of arguments. -// Based on https://groups.google.com/forum/#!topic/comp.std.c/d-6Mj5Lko_s. -#define FMT_NARG(...) FMT_NARG_(__VA_ARGS__, FMT_RSEQ_N()) -#define FMT_NARG_(...) FMT_EXPAND(FMT_ARG_N(__VA_ARGS__)) -#define FMT_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N -#define FMT_RSEQ_N() 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 - -#define FMT_CONCAT(a, b) a##b -#define FMT_FOR_EACH_(N, f, ...) FMT_EXPAND(FMT_CONCAT(FMT_FOR_EACH, N)(f, __VA_ARGS__)) -#define FMT_FOR_EACH(f, ...) FMT_EXPAND(FMT_FOR_EACH_(FMT_NARG(__VA_ARGS__), f, __VA_ARGS__)) - -#define FMT_ADD_ARG_NAME(type, index) type arg##index -#define FMT_GET_ARG_NAME(type, index) arg##index - -#if FMT_USE_VARIADIC_TEMPLATES -#define FMT_VARIADIC_(Char, ReturnType, func, call, ...) \ - template \ - ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__), const Args&... args) { \ - typename fmt::internal::ArgArray::Type array; \ - call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), \ - fmt::internal::make_arg_list>(array, args...)); \ - } -#else -// Defines a wrapper for a function taking __VA_ARGS__ arguments -// and n additional arguments of arbitrary types. -#define FMT_WRAP(Char, ReturnType, func, call, n, ...) \ - template \ - inline ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__), \ - FMT_GEN(n, FMT_MAKE_ARG)) { \ - fmt::internal::ArgArray::Type arr; \ - FMT_GEN(n, FMT_ASSIGN_##Char); \ - call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), \ - fmt::ArgList(fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), arr)); \ - } - -#define FMT_VARIADIC_(Char, ReturnType, func, call, ...) \ - inline ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__)) { \ - call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), fmt::ArgList()); \ - } \ - FMT_WRAP(Char, ReturnType, func, call, 1, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 2, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 3, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 4, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 5, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 6, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 7, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 8, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 9, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 10, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 11, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 12, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 13, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 14, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 15, __VA_ARGS__) -#endif // FMT_USE_VARIADIC_TEMPLATES - -/** -\rst -Defines a variadic function with the specified return type, function name -and argument types passed as variable arguments to this macro. - -**Example**:: - -void print_error(const char *file, int line, const char *format, -fmt::ArgList args) { -fmt::print("{}: {}: ", file, line); -fmt::print(format, args); -} -FMT_VARIADIC(void, print_error, const char *, int, const char *) - -``FMT_VARIADIC`` is used for compatibility with legacy C++ compilers that -don't implement variadic templates. You don't have to use this macro if -you don't need legacy compiler support and can use variadic templates -directly:: - -template -void print_error(const char *file, int line, const char *format, -const Args & ... args) { -fmt::print("{}: {}: ", file, line); -fmt::print(format, args...); -} -\endrst -*/ -#define FMT_VARIADIC(ReturnType, func, ...) \ - FMT_VARIADIC_(char, ReturnType, func, return func, __VA_ARGS__) - -#define FMT_VARIADIC_W(ReturnType, func, ...) \ - FMT_VARIADIC_(wchar_t, ReturnType, func, return func, __VA_ARGS__) - -#define FMT_CAPTURE_ARG_(id, index) ::fmt::arg(#id, id) - -#define FMT_CAPTURE_ARG_W_(id, index) ::fmt::arg(L## #id, id) - -/** -\rst -Convenient macro to capture the arguments' names and values into several -``fmt::arg(name, value)``. - -**Example**:: - -int x = 1, y = 2; -print("point: ({x}, {y})", FMT_CAPTURE(x, y)); -// same as: -// print("point: ({x}, {y})", arg("x", x), arg("y", y)); - -\endrst -*/ -#define FMT_CAPTURE(...) FMT_FOR_EACH(FMT_CAPTURE_ARG_, __VA_ARGS__) - -#define FMT_CAPTURE_W(...) FMT_FOR_EACH(FMT_CAPTURE_ARG_W_, __VA_ARGS__) - -namespace fmt { -FMT_VARIADIC(std::string, format, CStringRef) -FMT_VARIADIC_W(std::wstring, format, WCStringRef) -FMT_VARIADIC(void, print, CStringRef) -FMT_VARIADIC(void, print, std::FILE*, CStringRef) - -FMT_VARIADIC(void, print_colored, Color, CStringRef) -FMT_VARIADIC(std::string, sprintf, CStringRef) -FMT_VARIADIC_W(std::wstring, sprintf, WCStringRef) -FMT_VARIADIC(int, printf, CStringRef) -FMT_VARIADIC(int, fprintf, std::FILE*, CStringRef) - -#if FMT_USE_IOSTREAMS -/** -\rst -Prints formatted data to the stream *os*. - -**Example**:: - -print(cerr, "Don't {}!", "panic"); -\endrst -*/ -FMT_API void print(std::ostream& os, CStringRef format_str, ArgList args); -FMT_VARIADIC(void, print, std::ostream&, CStringRef) -#endif - -namespace internal { -template -inline bool -is_name_start(Char c) { - return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || '_' == c; -} - -// Parses an unsigned integer advancing s to the end of the parsed input. -// This function assumes that the first character of s is a digit. -template -int -parse_nonnegative_int(const Char*& s) { - assert('0' <= *s && *s <= '9'); - unsigned value = 0; - do { - unsigned new_value = value * 10 + (*s++ - '0'); - // Check if value wrapped around. - if (new_value < value) { - value = (std::numeric_limits::max)(); - break; - } - value = new_value; - } while ('0' <= *s && *s <= '9'); - // Convert to unsigned to prevent a warning. - unsigned max_int = (std::numeric_limits::max)(); - if (value > max_int) FMT_THROW(FormatError("number is too big")); - return value; -} - -inline void -require_numeric_argument(const Arg& arg, char spec) { - if (arg.type > Arg::LAST_NUMERIC_TYPE) { - std::string message = fmt::format("format specifier '{}' requires numeric argument", spec); - FMT_THROW(fmt::FormatError(message)); - } -} - -template -void -check_sign(const Char*& s, const Arg& arg) { - char sign = static_cast(*s); - require_numeric_argument(arg, sign); - if (arg.type == Arg::UINT || arg.type == Arg::ULONG_LONG) { - FMT_THROW(FormatError(fmt::format("format specifier '{}' requires signed argument", sign))); - } - ++s; -} -} // namespace internal - -template -inline internal::Arg -BasicFormatter::get_arg(BasicStringRef arg_name, const char*& error) { - if (check_no_auto_index(error)) { - map_.init(args()); - const internal::Arg* arg = map_.find(arg_name); - if (arg) return *arg; - error = "argument not found"; - } - return internal::Arg(); -} - -template -inline internal::Arg -BasicFormatter::parse_arg_index(const Char*& s) { - const char* error = 0; - internal::Arg arg = - *s < '0' || *s > '9' ? next_arg(error) : get_arg(internal::parse_nonnegative_int(s), error); - if (error) { FMT_THROW(FormatError(*s != '}' && *s != ':' ? "invalid format string" : error)); } - return arg; -} - -template -inline internal::Arg -BasicFormatter::parse_arg_name(const Char*& s) { - assert(internal::is_name_start(*s)); - const Char* start = s; - Char c; - do { c = *++s; } while (internal::is_name_start(c) || ('0' <= c && c <= '9')); - const char* error = 0; - internal::Arg arg = get_arg(BasicStringRef(start, s - start), error); - if (error) FMT_THROW(FormatError(error)); - return arg; -} - -// Should be after FormatSpec -template -const Char* -BasicFormatter::format(const Char*& format_str, const internal::Arg& arg) { - using internal::Arg; - const Char* s = format_str; - FormatSpec spec; - if (*s == ':') { - if (arg.type == Arg::CUSTOM) { - arg.custom.format(this, arg.custom.value, &s); - return s; - } - ++s; - // Parse fill and alignment. - if (Char c = *s) { - const Char* p = s + 1; - spec.align_ = ALIGN_DEFAULT; - do { - switch (*p) { - case '<': spec.align_ = ALIGN_LEFT; break; - case '>': spec.align_ = ALIGN_RIGHT; break; - case '=': spec.align_ = ALIGN_NUMERIC; break; - case '^': spec.align_ = ALIGN_CENTER; break; - } - if (spec.align_ != ALIGN_DEFAULT) { - if (p != s) { - if (c == '}') break; - if (c == '{') FMT_THROW(FormatError("invalid fill character '{'")); - s += 2; - spec.fill_ = c; - } else - ++s; - if (spec.align_ == ALIGN_NUMERIC) require_numeric_argument(arg, '='); - break; - } - } while (--p >= s); - } - - // Parse sign. - switch (*s) { - case '+': - check_sign(s, arg); - spec.flags_ |= SIGN_FLAG | PLUS_FLAG; - break; - case '-': - check_sign(s, arg); - spec.flags_ |= MINUS_FLAG; - break; - case ' ': - check_sign(s, arg); - spec.flags_ |= SIGN_FLAG; - break; - } - - if (*s == '#') { - require_numeric_argument(arg, '#'); - spec.flags_ |= HASH_FLAG; - ++s; - } - - // Parse zero flag. - if (*s == '0') { - require_numeric_argument(arg, '0'); - spec.align_ = ALIGN_NUMERIC; - spec.fill_ = '0'; - ++s; - } - - // Parse width. - if ('0' <= *s && *s <= '9') { - spec.width_ = internal::parse_nonnegative_int(s); - } else if (*s == '{') { - ++s; - Arg width_arg = internal::is_name_start(*s) ? parse_arg_name(s) : parse_arg_index(s); - if (*s++ != '}') FMT_THROW(FormatError("invalid format string")); - ULongLong value = 0; - switch (width_arg.type) { - case Arg::INT: - if (width_arg.int_value < 0) FMT_THROW(FormatError("negative width")); - value = width_arg.int_value; - break; - case Arg::UINT: value = width_arg.uint_value; break; - case Arg::LONG_LONG: - if (width_arg.long_long_value < 0) FMT_THROW(FormatError("negative width")); - value = width_arg.long_long_value; - break; - case Arg::ULONG_LONG: value = width_arg.ulong_long_value; break; - default: FMT_THROW(FormatError("width is not integer")); - } - if (value > (std::numeric_limits::max)()) - FMT_THROW(FormatError("number is too big")); - spec.width_ = static_cast(value); - } - - // Parse precision. - if (*s == '.') { - ++s; - spec.precision_ = 0; - if ('0' <= *s && *s <= '9') { - spec.precision_ = internal::parse_nonnegative_int(s); - } else if (*s == '{') { - ++s; - Arg precision_arg = - internal::is_name_start(*s) ? parse_arg_name(s) : parse_arg_index(s); - if (*s++ != '}') FMT_THROW(FormatError("invalid format string")); - ULongLong value = 0; - switch (precision_arg.type) { - case Arg::INT: - if (precision_arg.int_value < 0) FMT_THROW(FormatError("negative precision")); - value = precision_arg.int_value; - break; - case Arg::UINT: value = precision_arg.uint_value; break; - case Arg::LONG_LONG: - if (precision_arg.long_long_value < 0) - FMT_THROW(FormatError("negative precision")); - value = precision_arg.long_long_value; - break; - case Arg::ULONG_LONG: value = precision_arg.ulong_long_value; break; - default: FMT_THROW(FormatError("precision is not integer")); - } - if (value > (std::numeric_limits::max)()) - FMT_THROW(FormatError("number is too big")); - spec.precision_ = static_cast(value); - } else { - FMT_THROW(FormatError("missing precision specifier")); - } - if (arg.type <= Arg::LAST_INTEGER_TYPE || arg.type == Arg::POINTER) { - FMT_THROW( - FormatError(fmt::format("precision not allowed in {} format specifier", - arg.type == Arg::POINTER ? "pointer" : "integer"))); - } - } - - // Parse type. - if (*s != '}' && *s) spec.type_ = static_cast(*s++); - } - - if (*s++ != '}') FMT_THROW(FormatError("missing '}' in format string")); - - // Format argument. - internal::BasicArgFormatter(*this, spec, s - 1).visit(arg); - return s; -} - -template -void -BasicFormatter::format(BasicCStringRef format_str) { - const Char* s = format_str.c_str(); - const Char* start = s; - while (*s) { - Char c = *s++; - if (c != '{' && c != '}') continue; - if (*s == c) { - write(writer_, start, s); - start = ++s; - continue; - } - if (c == '}') FMT_THROW(FormatError("unmatched '}' in format string")); - write(writer_, start, s - 1); - internal::Arg arg = internal::is_name_start(*s) ? parse_arg_name(s) : parse_arg_index(s); - start = s = format(s, arg); - } - write(writer_, start, s); -} -} // namespace fmt - -#if FMT_USE_USER_DEFINED_LITERALS -namespace fmt { -namespace internal { - -template -struct UdlFormat { - const Char* str; - - template - auto operator()(Args&&... args) const -> decltype(format(str, std::forward(args)...)) { - return format(str, std::forward(args)...); - } -}; - -template -struct UdlArg { - const Char* str; - - template - NamedArg operator=(T&& value) const { - return { str, std::forward(value) }; - } -}; - -} // namespace internal - -inline namespace literals { -/** -\rst -C++11 literal equivalent of :func:`fmt::format`. - -**Example**:: - -using namespace fmt::literals; -std::string message = "The answer is {}"_format(42); -\endrst -*/ -inline internal::UdlFormat operator"" _format(const char* s, std::size_t) { return { s }; } -inline internal::UdlFormat operator"" _format(const wchar_t* s, std::size_t) { - return { s }; -} - -/** -\rst -C++11 literal equivalent of :func:`fmt::arg`. - -**Example**:: - -using namespace fmt::literals; -print("Elapsed time: {s:.2f} seconds", "s"_a=1.23); -\endrst -*/ -inline internal::UdlArg operator"" _a(const char* s, std::size_t) { return { s }; } -inline internal::UdlArg operator"" _a(const wchar_t* s, std::size_t) { return { s }; } - -} // inline namespace literals -} // namespace fmt -#endif // FMT_USE_USER_DEFINED_LITERALS - -// Restore warnings. -#if FMT_GCC_VERSION >= 406 -#pragma GCC diagnostic pop -#endif - -#if defined(__clang__) && !defined(__INTEL_COMPILER) -#pragma clang diagnostic pop -#endif - -#ifdef FMT_HEADER_ONLY -#include "format.cc" -#endif - -#endif // FMT_FORMAT_H_ \ No newline at end of file diff --git a/cameradar_standalone/include/spdlog/details/line_logger.h b/cameradar_standalone/include/spdlog/details/line_logger.h deleted file mode 100644 index 6730d45..0000000 --- a/cameradar_standalone/include/spdlog/details/line_logger.h +++ /dev/null @@ -1,156 +0,0 @@ -// -// Copyright(c) 2015 Gabi Melman. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) -// -#pragma once -#include -#include "../common.h" -#include "../logger.h" - -// Line logger class - aggregates operator<< calls to fast ostream -// and logs upon destruction - -namespace spdlog { -namespace details { -class line_logger { -public: - line_logger(logger* callback_logger, level::level_enum msg_level, bool enabled) - : _callback_logger(callback_logger), _log_msg(msg_level), _enabled(enabled) {} - - // No copy intended. Only move - line_logger(const line_logger& other) = delete; - line_logger& operator=(const line_logger&) = delete; - line_logger& operator=(line_logger&&) = delete; - - line_logger(line_logger&& other) - : _callback_logger(other._callback_logger) - , _log_msg(std::move(other._log_msg)) - , _enabled(other._enabled) { - other.disable(); - } - - // Log the log message using the callback logger - ~line_logger() { - if (_enabled) { -#ifndef SPDLOG_NO_NAME - _log_msg.logger_name = _callback_logger->name(); -#endif -#ifndef SPDLOG_NO_DATETIME - _log_msg.time = os::now(); -#endif - -#ifndef SPDLOG_NO_THREAD_ID - _log_msg.thread_id = os::thread_id(); -#endif - _callback_logger->_log_msg(_log_msg); - } - } - - // - // Support for format string with variadic args - // - - void - write(const char* what) { - if (_enabled) _log_msg.raw << what; - } - - template - void - write(const char* fmt, const Args&... args) { - if (!_enabled) return; - try { - _log_msg.raw.write(fmt, args...); - } catch (const fmt::FormatError& e) { - throw spdlog_ex(fmt::format( - "formatting error while processing format string '{}': {}", fmt, e.what())); - } - } - - // - // Support for operator<< - // - line_logger& operator<<(const char* what) { - if (_enabled) _log_msg.raw << what; - return *this; - } - - line_logger& operator<<(const std::string& what) { - if (_enabled) _log_msg.raw << what; - return *this; - } - - line_logger& operator<<(int what) { - if (_enabled) _log_msg.raw << what; - return *this; - } - - line_logger& operator<<(unsigned int what) { - if (_enabled) _log_msg.raw << what; - return *this; - } - - line_logger& operator<<(long what) { - if (_enabled) _log_msg.raw << what; - return *this; - } - - line_logger& operator<<(unsigned long what) { - if (_enabled) _log_msg.raw << what; - return *this; - } - - line_logger& operator<<(long long what) { - if (_enabled) _log_msg.raw << what; - return *this; - } - - line_logger& operator<<(unsigned long long what) { - if (_enabled) _log_msg.raw << what; - return *this; - } - - line_logger& operator<<(double what) { - if (_enabled) _log_msg.raw << what; - return *this; - } - - line_logger& operator<<(long double what) { - if (_enabled) _log_msg.raw << what; - return *this; - } - - line_logger& operator<<(float what) { - if (_enabled) _log_msg.raw << what; - return *this; - } - - line_logger& operator<<(char what) { - if (_enabled) _log_msg.raw << what; - return *this; - } - - // Support user types which implements operator<< - template - line_logger& operator<<(const T& what) { - if (_enabled) _log_msg.raw.write("{}", what); - return *this; - } - - void - disable() { - _enabled = false; - } - - bool - is_enabled() const { - return _enabled; - } - -private: - logger* _callback_logger; - log_msg _log_msg; - bool _enabled; -}; -} // Namespace details -} // Namespace spdlog diff --git a/cameradar_standalone/include/spdlog/details/log_msg.h b/cameradar_standalone/include/spdlog/details/log_msg.h deleted file mode 100644 index bae2fb2..0000000 --- a/cameradar_standalone/include/spdlog/details/log_msg.h +++ /dev/null @@ -1,79 +0,0 @@ -// -// Copyright(c) 2015 Gabi Melman. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) -// - -#pragma once - -#include -#include "../common.h" -#include "./format.h" - -namespace spdlog -{ -namespace details -{ -struct log_msg -{ - log_msg() = default; - log_msg(level::level_enum l): - logger_name(), - level(l), - raw(), - formatted() {} - - - log_msg(const log_msg& other) : - logger_name(other.logger_name), - level(other.level), - time(other.time), - thread_id(other.thread_id) - { - if (other.raw.size()) - raw << fmt::BasicStringRef(other.raw.data(), other.raw.size()); - if (other.formatted.size()) - formatted << fmt::BasicStringRef(other.formatted.data(), other.formatted.size()); - } - - log_msg(log_msg&& other) : - logger_name(std::move(other.logger_name)), - level(other.level), - time(std::move(other.time)), - thread_id(other.thread_id), - raw(std::move(other.raw)), - formatted(std::move(other.formatted)) - { - other.clear(); - } - - log_msg& operator=(log_msg&& other) - { - if (this == &other) - return *this; - - logger_name = std::move(other.logger_name); - level = other.level; - time = std::move(other.time); - thread_id = other.thread_id; - raw = std::move(other.raw); - formatted = std::move(other.formatted); - other.clear(); - return *this; - } - - void clear() - { - level = level::off; - raw.clear(); - formatted.clear(); - } - - std::string logger_name; - level::level_enum level; - log_clock::time_point time; - size_t thread_id; - fmt::MemoryWriter raw; - fmt::MemoryWriter formatted; -}; -} -} diff --git a/cameradar_standalone/include/spdlog/details/logger_impl.h b/cameradar_standalone/include/spdlog/details/logger_impl.h deleted file mode 100644 index 7f0171e..0000000 --- a/cameradar_standalone/include/spdlog/details/logger_impl.h +++ /dev/null @@ -1,299 +0,0 @@ -// -// Copyright(c) 2015 Gabi Melman. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) -// - -#pragma once - -#include "./line_logger.h" - -// create logger with given name, sinks and the default pattern formatter -// all other ctors will call this one -template -inline spdlog::logger::logger(const std::string& logger_name, const It& begin, const It& end) : - _name(logger_name), - _sinks(begin, end), - _formatter(std::make_shared("%+")) -{ - - // no support under vs2013 for member initialization for std::atomic - _level = level::info; -} - -// ctor with sinks as init list -inline spdlog::logger::logger(const std::string& logger_name, sinks_init_list sinks_list) : - logger(logger_name, sinks_list.begin(), sinks_list.end()) {} - - -// ctor with single sink -inline spdlog::logger::logger(const std::string& logger_name, spdlog::sink_ptr single_sink) : - logger(logger_name, -{ - single_sink -}) {} - - -inline spdlog::logger::~logger() = default; - - -inline void spdlog::logger::set_formatter(spdlog::formatter_ptr msg_formatter) -{ - _set_formatter(msg_formatter); -} - -inline void spdlog::logger::set_pattern(const std::string& pattern) -{ - _set_pattern(pattern); -} - -// -// log only if given level>=logger's log level -// - - -template -inline spdlog::details::line_logger spdlog::logger::_log_if_enabled(level::level_enum lvl, const char* fmt, const Args&... args) -{ - bool msg_enabled = should_log(lvl); - details::line_logger l(this, lvl, msg_enabled); - l.write(fmt, args...); - return l; -} - -inline spdlog::details::line_logger spdlog::logger::_log_if_enabled(level::level_enum lvl) -{ - return details::line_logger(this, lvl, should_log(lvl)); -} - -template -inline spdlog::details::line_logger spdlog::logger::_log_if_enabled(level::level_enum lvl, const T& msg) -{ - bool msg_enabled = should_log(lvl); - details::line_logger l(this, lvl, msg_enabled); - l << msg; - return l; -} - -// -// logger.info(cppformat_string, arg1, arg2, arg3, ...) call style -// -template -inline spdlog::details::line_logger spdlog::logger::trace(const char* fmt, const Args&... args) -{ - return _log_if_enabled(level::trace, fmt, args...); -} - -template -inline spdlog::details::line_logger spdlog::logger::debug(const char* fmt, const Args&... args) -{ - return _log_if_enabled(level::debug, fmt, args...); -} - -template -inline spdlog::details::line_logger spdlog::logger::info(const char* fmt, const Args&... args) -{ - return _log_if_enabled(level::info, fmt, args...); -} - -template -inline spdlog::details::line_logger spdlog::logger::notice(const char* fmt, const Args&... args) -{ - return _log_if_enabled(level::notice, fmt, args...); -} - -template -inline spdlog::details::line_logger spdlog::logger::warn(const char* fmt, const Args&... args) -{ - return _log_if_enabled(level::warn, fmt, args...); -} - -template -inline spdlog::details::line_logger spdlog::logger::error(const char* fmt, const Args&... args) -{ - return _log_if_enabled(level::err, fmt, args...); -} - -template -inline spdlog::details::line_logger spdlog::logger::critical(const char* fmt, const Args&... args) -{ - return _log_if_enabled(level::critical, fmt, args...); -} - -template -inline spdlog::details::line_logger spdlog::logger::alert(const char* fmt, const Args&... args) -{ - return _log_if_enabled(level::alert, fmt, args...); -} - -template -inline spdlog::details::line_logger spdlog::logger::emerg(const char* fmt, const Args&... args) -{ - return _log_if_enabled(level::emerg, fmt, args...); -} - -// -// logger.info(msg) << ".." call style -// -template -inline spdlog::details::line_logger spdlog::logger::trace(const T& msg) -{ - return _log_if_enabled(level::trace, msg); -} - -template -inline spdlog::details::line_logger spdlog::logger::debug(const T& msg) -{ - return _log_if_enabled(level::debug, msg); -} - - -template -inline spdlog::details::line_logger spdlog::logger::info(const T& msg) -{ - return _log_if_enabled(level::info, msg); -} - -template -inline spdlog::details::line_logger spdlog::logger::notice(const T& msg) -{ - return _log_if_enabled(level::notice, msg); -} - -template -inline spdlog::details::line_logger spdlog::logger::warn(const T& msg) -{ - return _log_if_enabled(level::warn, msg); -} - -template -inline spdlog::details::line_logger spdlog::logger::error(const T& msg) -{ - return _log_if_enabled(level::err, msg); -} - -template -inline spdlog::details::line_logger spdlog::logger::critical(const T& msg) -{ - return _log_if_enabled(level::critical, msg); -} - -template -inline spdlog::details::line_logger spdlog::logger::alert(const T& msg) -{ - return _log_if_enabled(level::alert, msg); -} - -template -inline spdlog::details::line_logger spdlog::logger::emerg(const T& msg) -{ - return _log_if_enabled(level::emerg, msg); -} - - - - -// -// logger.info() << ".." call style -// -inline spdlog::details::line_logger spdlog::logger::trace() -{ - return _log_if_enabled(level::trace); -} - -inline spdlog::details::line_logger spdlog::logger::debug() -{ - return _log_if_enabled(level::debug); -} - -inline spdlog::details::line_logger spdlog::logger::info() -{ - return _log_if_enabled(level::info); -} - -inline spdlog::details::line_logger spdlog::logger::notice() -{ - return _log_if_enabled(level::notice); -} - -inline spdlog::details::line_logger spdlog::logger::warn() -{ - return _log_if_enabled(level::warn); -} - -inline spdlog::details::line_logger spdlog::logger::error() -{ - return _log_if_enabled(level::err); -} - -inline spdlog::details::line_logger spdlog::logger::critical() -{ - return _log_if_enabled(level::critical); -} - -inline spdlog::details::line_logger spdlog::logger::alert() -{ - return _log_if_enabled(level::alert); -} - -inline spdlog::details::line_logger spdlog::logger::emerg() -{ - return _log_if_enabled(level::emerg); -} - - -// always log, no matter what is the actual logger's log level -template -inline spdlog::details::line_logger spdlog::logger::force_log(level::level_enum lvl, const char* fmt, const Args&... args) -{ - details::line_logger l(this, lvl, true); - l.write(fmt, args...); - return l; -} - -// -// name and level -// -inline const std::string& spdlog::logger::name() const -{ - return _name; -} - -inline void spdlog::logger::set_level(spdlog::level::level_enum log_level) -{ - _level.store(log_level); -} - -inline spdlog::level::level_enum spdlog::logger::level() const -{ - return static_cast(_level.load(std::memory_order_relaxed)); -} - -inline bool spdlog::logger::should_log(spdlog::level::level_enum msg_level) const -{ - return msg_level >= _level.load(std::memory_order_relaxed); -} - -// -// protected virtual called at end of each user log call (if enabled) by the line_logger -// -inline void spdlog::logger::_log_msg(details::log_msg& msg) -{ - _formatter->format(msg); - for (auto &sink : _sinks) - sink->log(msg); -} - -inline void spdlog::logger::_set_pattern(const std::string& pattern) -{ - _formatter = std::make_shared(pattern); -} -inline void spdlog::logger::_set_formatter(formatter_ptr msg_formatter) -{ - _formatter = msg_formatter; -} - -inline void spdlog::logger::flush() -{ - for (auto& sink : _sinks) - sink->flush(); -} \ No newline at end of file diff --git a/cameradar_standalone/include/spdlog/details/mpmc_bounded_q.h b/cameradar_standalone/include/spdlog/details/mpmc_bounded_q.h deleted file mode 100644 index 26bda5f..0000000 --- a/cameradar_standalone/include/spdlog/details/mpmc_bounded_q.h +++ /dev/null @@ -1,157 +0,0 @@ -/* -A modified version of Bounded MPMC queue by Dmitry Vyukov. - -Original code from: -http://www.1024cores.net/home/lock-free-algorithms/queues/bounded-mpmc-queue - -licensed by Dmitry Vyukov under the terms below: - -Simplified BSD license - -Copyright (c) 2010-2011 Dmitry Vyukov. All rights reserved. -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: -1. Redistributions of source code must retain the above copyright notice, this list of -conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, this list -of conditions and the following disclaimer in the documentation and/or other materials -provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY DMITRY VYUKOV "AS IS" AND ANY EXPRESS OR IMPLIED -WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -SHALL DMITRY VYUKOV OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, -OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE -OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -The views and conclusions contained in the software and documentation are those of the authors and -should not be interpreted as representing official policies, either expressed or implied, of Dmitry Vyukov. -*/ - -/* -The code in its current form adds the license below: - -Copyright(c) 2015 Gabi Melman. -Distributed under the MIT License (http://opensource.org/licenses/MIT) - -*/ - -#pragma once - -#include -#include "../common.h" - -namespace spdlog -{ -namespace details -{ - -template -class mpmc_bounded_queue -{ -public: - - using item_type = T; - mpmc_bounded_queue(size_t buffer_size) - : buffer_(new cell_t [buffer_size]), - buffer_mask_(buffer_size - 1) - { - //queue size must be power of two - if(!((buffer_size >= 2) && ((buffer_size & (buffer_size - 1)) == 0))) - throw spdlog_ex("async logger queue size must be power of two"); - - for (size_t i = 0; i != buffer_size; i += 1) - buffer_[i].sequence_.store(i, std::memory_order_relaxed); - enqueue_pos_.store(0, std::memory_order_relaxed); - dequeue_pos_.store(0, std::memory_order_relaxed); - } - - ~mpmc_bounded_queue() - { - delete [] buffer_; - } - - - bool enqueue(T&& data) - { - cell_t* cell; - size_t pos = enqueue_pos_.load(std::memory_order_relaxed); - for (;;) - { - cell = &buffer_[pos & buffer_mask_]; - size_t seq = cell->sequence_.load(std::memory_order_acquire); - intptr_t dif = (intptr_t)seq - (intptr_t)pos; - if (dif == 0) - { - if (enqueue_pos_.compare_exchange_weak(pos, pos + 1, std::memory_order_relaxed)) - break; - } - else if (dif < 0) - { - return false; - } - else - { - pos = enqueue_pos_.load(std::memory_order_relaxed); - } - } - cell->data_ = std::move(data); - cell->sequence_.store(pos + 1, std::memory_order_release); - return true; - } - - bool dequeue(T& data) - { - cell_t* cell; - size_t pos = dequeue_pos_.load(std::memory_order_relaxed); - for (;;) - { - cell = &buffer_[pos & buffer_mask_]; - size_t seq = - cell->sequence_.load(std::memory_order_acquire); - intptr_t dif = (intptr_t)seq - (intptr_t)(pos + 1); - if (dif == 0) - { - if (dequeue_pos_.compare_exchange_weak(pos, pos + 1, std::memory_order_relaxed)) - break; - } - else if (dif < 0) - return false; - else - pos = dequeue_pos_.load(std::memory_order_relaxed); - } - data = std::move(cell->data_); - cell->sequence_.store(pos + buffer_mask_ + 1, std::memory_order_release); - return true; - } - -private: - struct cell_t - { - std::atomic sequence_; - T data_; - }; - - static size_t const cacheline_size = 64; - typedef char cacheline_pad_t [cacheline_size]; - - cacheline_pad_t pad0_; - cell_t* const buffer_; - size_t const buffer_mask_; - cacheline_pad_t pad1_; - std::atomic enqueue_pos_; - cacheline_pad_t pad2_; - std::atomic dequeue_pos_; - cacheline_pad_t pad3_; - - mpmc_bounded_queue(mpmc_bounded_queue const&); - void operator = (mpmc_bounded_queue const&); -}; - -} // ns details -} // ns spdlog diff --git a/cameradar_standalone/include/spdlog/details/null_mutex.h b/cameradar_standalone/include/spdlog/details/null_mutex.h deleted file mode 100644 index 19e90bf..0000000 --- a/cameradar_standalone/include/spdlog/details/null_mutex.h +++ /dev/null @@ -1,24 +0,0 @@ -// -// Copyright(c) 2015 Gabi Melman. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) -// - -#pragma once - -// null, no cost mutex - -namespace spdlog -{ -namespace details -{ -struct null_mutex -{ - void lock() {} - void unlock() {} - bool try_lock() - { - return true; - } -}; -} -} diff --git a/cameradar_standalone/include/spdlog/details/os.h b/cameradar_standalone/include/spdlog/details/os.h deleted file mode 100644 index 30e2f6d..0000000 --- a/cameradar_standalone/include/spdlog/details/os.h +++ /dev/null @@ -1,215 +0,0 @@ -// -// Copyright(c) 2015 Gabi Melman. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) -// -#pragma once - -#include -#include -#include - -#ifdef _WIN32 -# ifndef WIN32_LEAN_AND_MEAN -# define WIN32_LEAN_AND_MEAN -# endif -# include - -#ifdef __MINGW32__ -#include -#endif - -#elif __linux__ -#include //Use gettid() syscall under linux to get thread id -#include -#include -#else -#include -#endif - -#include "../common.h" - -namespace spdlog -{ -namespace details -{ -namespace os -{ - -inline spdlog::log_clock::time_point now() -{ - -#if defined __linux__ && defined SPDLOG_CLOCK_COARSE - timespec ts; - ::clock_gettime(CLOCK_REALTIME_COARSE, &ts); - return std::chrono::time_point( - std::chrono::duration_cast( - std::chrono::seconds(ts.tv_sec) + std::chrono::nanoseconds(ts.tv_nsec))); - - -#else - return log_clock::now(); -#endif - -} -inline std::tm localtime(const std::time_t &time_tt) -{ - -#ifdef _WIN32 - std::tm tm; - localtime_s(&tm, &time_tt); -#else - std::tm tm; - localtime_r(&time_tt, &tm); -#endif - return tm; -} - -inline std::tm localtime() -{ - std::time_t now_t = time(nullptr); - return localtime(now_t); -} - - -inline std::tm gmtime(const std::time_t &time_tt) -{ - -#ifdef _WIN32 - std::tm tm; - gmtime_s(&tm, &time_tt); -#else - std::tm tm; - gmtime_r(&time_tt, &tm); -#endif - return tm; -} - -inline std::tm gmtime() -{ - std::time_t now_t = time(nullptr); - return gmtime(now_t); -} -inline bool operator==(const std::tm& tm1, const std::tm& tm2) -{ - return (tm1.tm_sec == tm2.tm_sec && - tm1.tm_min == tm2.tm_min && - tm1.tm_hour == tm2.tm_hour && - tm1.tm_mday == tm2.tm_mday && - tm1.tm_mon == tm2.tm_mon && - tm1.tm_year == tm2.tm_year && - tm1.tm_isdst == tm2.tm_isdst); -} - -inline bool operator!=(const std::tm& tm1, const std::tm& tm2) -{ - return !(tm1 == tm2); -} - -#ifdef _WIN32 -inline const char* eol() -{ - return "\r\n"; -} -#else -constexpr inline const char* eol() -{ - return "\n"; -} -#endif - -#ifdef _WIN32 -inline unsigned short eol_size() -{ - return 2; -} -#else -constexpr inline unsigned short eol_size() -{ - return 1; -} -#endif - -//fopen_s on non windows for writing -inline int fopen_s(FILE** fp, const std::string& filename, const char* mode) -{ -#ifdef _WIN32 - *fp = _fsopen((filename.c_str()), mode, _SH_DENYWR); - return *fp == nullptr; -#else - *fp = fopen((filename.c_str()), mode); - return *fp == nullptr; -#endif - -} - - -//Return if file exists -inline bool file_exists(const std::string& filename) -{ -#ifdef _WIN32 - auto attribs = GetFileAttributesA(filename.c_str()); - return (attribs != INVALID_FILE_ATTRIBUTES && !(attribs & FILE_ATTRIBUTE_DIRECTORY)); -#elif __linux__ - struct stat buffer; - return (stat (filename.c_str(), &buffer) == 0); -#else - auto *file = fopen(filename.c_str(), "r"); - if (file != nullptr) - { - fclose(file); - return true; - } - return false; - -#endif - -} - -//Return utc offset in minutes or throw spdlog_ex on failure -inline int utc_minutes_offset(const std::tm& tm = details::os::localtime()) -{ - -#ifdef _WIN32 -#if _WIN32_WINNT < _WIN32_WINNT_WS08 - TIME_ZONE_INFORMATION tzinfo; - auto rv = GetTimeZoneInformation(&tzinfo); -#else - DYNAMIC_TIME_ZONE_INFORMATION tzinfo; - auto rv = GetDynamicTimeZoneInformation(&tzinfo); -#endif - if (rv == TIME_ZONE_ID_INVALID) - throw spdlog::spdlog_ex("Failed getting timezone info. Last error: " + GetLastError()); - - int offset = -tzinfo.Bias; - if (tm.tm_isdst) - offset -= tzinfo.DaylightBias; - else - offset -= tzinfo.StandardBias; - return offset; -#else - return static_cast(tm.tm_gmtoff / 60); -#endif -} - -//Return current thread id as size_t -//It exists because the std::this_thread::get_id() is much slower(espcially under VS 2013) -inline size_t thread_id() -{ -#ifdef _WIN32 - return static_cast(::GetCurrentThreadId()); -#elif __linux__ -# if defined(__ANDROID__) && defined(__ANDROID_API__) && (__ANDROID_API__ < 21) -# define SYS_gettid __NR_gettid -# endif - return static_cast(syscall(SYS_gettid)); -#else //Default to standard C++11 (OSX and other Unix) - return static_cast(std::hash()(std::this_thread::get_id())); -#endif - -} - -} //os -} //details -} //spdlog - - diff --git a/cameradar_standalone/include/spdlog/details/pattern_formatter_impl.h b/cameradar_standalone/include/spdlog/details/pattern_formatter_impl.h deleted file mode 100644 index 92ccc37..0000000 --- a/cameradar_standalone/include/spdlog/details/pattern_formatter_impl.h +++ /dev/null @@ -1,625 +0,0 @@ -// -// Copyright(c) 2015 Gabi Melman. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) -// - -#pragma once - -#include -#include -#include -#include -#include - - -#include "../formatter.h" -#include "./log_msg.h" -#include "./os.h" - -namespace spdlog -{ -namespace details -{ -class flag_formatter -{ -public: - virtual ~flag_formatter() {} - virtual void format(details::log_msg& msg, const std::tm& tm_time) = 0; -}; - -/////////////////////////////////////////////////////////////////////// -// name & level pattern appenders -/////////////////////////////////////////////////////////////////////// -namespace -{ -class name_formatter :public flag_formatter -{ - void format(details::log_msg& msg, const std::tm&) override - { - msg.formatted << msg.logger_name; - } -}; -} - -// log level appender -class level_formatter :public flag_formatter -{ - void format(details::log_msg& msg, const std::tm&) override - { - msg.formatted << level::to_str(msg.level); - } -}; - -// short log level appender -class short_level_formatter :public flag_formatter -{ - void format(details::log_msg& msg, const std::tm&) override - { - msg.formatted << level::to_short_str(msg.level); - } -}; - -/////////////////////////////////////////////////////////////////////// -// Date time pattern appenders -/////////////////////////////////////////////////////////////////////// - -static const char* ampm(const tm& t) -{ - return t.tm_hour >= 12 ? "PM" : "AM"; -} - -static int to12h(const tm& t) -{ - return t.tm_hour > 12 ? t.tm_hour - 12 : t.tm_hour; -} - -//Abbreviated weekday name -static const std::string days[] { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; -class a_formatter :public flag_formatter -{ - void format(details::log_msg& msg, const std::tm& tm_time) override - { - msg.formatted << days[tm_time.tm_wday]; - } -}; - -//Full weekday name -static const std::string full_days[] { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" }; -class A_formatter :public flag_formatter -{ - void format(details::log_msg& msg, const std::tm& tm_time) override - { - msg.formatted << full_days[tm_time.tm_wday]; - } -}; - -//Abbreviated month -static const std::string months[] { "Jan", "Feb", "Mar", "Apr", "May", "June", "July", "Aug", "Sept", "Oct", "Nov", "Dec" }; -class b_formatter :public flag_formatter -{ - void format(details::log_msg& msg, const std::tm& tm_time) override - { - msg.formatted<< months[tm_time.tm_mon]; - } -}; - -//Full month name -static const std::string full_months[] { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; -class B_formatter :public flag_formatter -{ - void format(details::log_msg& msg, const std::tm& tm_time) override - { - msg.formatted << full_months[tm_time.tm_mon]; - } -}; - - -//write 2 ints seperated by sep with padding of 2 -static fmt::MemoryWriter& pad_n_join(fmt::MemoryWriter& w, int v1, int v2, char sep) -{ - w << fmt::pad(v1, 2, '0') << sep << fmt::pad(v2, 2, '0'); - return w; -} - -//write 3 ints seperated by sep with padding of 2 -static fmt::MemoryWriter& pad_n_join(fmt::MemoryWriter& w, int v1, int v2, int v3, char sep) -{ - w << fmt::pad(v1, 2, '0') << sep << fmt::pad(v2, 2, '0') << sep << fmt::pad(v3, 2, '0'); - return w; -} - - -//Date and time representation (Thu Aug 23 15:35:46 2014) -class c_formatter :public flag_formatter -{ - void format(details::log_msg& msg, const std::tm& tm_time) override - { - msg.formatted << days[tm_time.tm_wday] << ' ' << months[tm_time.tm_mon] << ' ' << tm_time.tm_mday << ' '; - pad_n_join(msg.formatted, tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec, ':') << ' ' << tm_time.tm_year + 1900; - } -}; - - -// year - 2 digit -class C_formatter :public flag_formatter -{ - void format(details::log_msg& msg, const std::tm& tm_time) override - { - msg.formatted << fmt::pad(tm_time.tm_year % 100, 2, '0'); - } -}; - - - -// Short MM/DD/YY date, equivalent to %m/%d/%y 08/23/01 -class D_formatter :public flag_formatter -{ - void format(details::log_msg& msg, const std::tm& tm_time) override - { - pad_n_join(msg.formatted, tm_time.tm_mon + 1, tm_time.tm_mday, tm_time.tm_year % 100, '/'); - } -}; - - -// year - 4 digit -class Y_formatter :public flag_formatter -{ - void format(details::log_msg& msg, const std::tm& tm_time) override - { - msg.formatted << tm_time.tm_year + 1900; - } -}; - -// month 1-12 -class m_formatter :public flag_formatter -{ - void format(details::log_msg& msg, const std::tm& tm_time) override - { - msg.formatted << fmt::pad(tm_time.tm_mon + 1, 2, '0'); - } -}; - -// day of month 1-31 -class d_formatter :public flag_formatter -{ - void format(details::log_msg& msg, const std::tm& tm_time) override - { - msg.formatted << fmt::pad(tm_time.tm_mday, 2, '0'); - } -}; - -// hours in 24 format 0-23 -class H_formatter :public flag_formatter -{ - void format(details::log_msg& msg, const std::tm& tm_time) override - { - msg.formatted << fmt::pad(tm_time.tm_hour, 2, '0'); - } -}; - -// hours in 12 format 1-12 -class I_formatter :public flag_formatter -{ - void format(details::log_msg& msg, const std::tm& tm_time) override - { - msg.formatted << fmt::pad(to12h(tm_time), 2, '0'); - } -}; - -// minutes 0-59 -class M_formatter :public flag_formatter -{ - void format(details::log_msg& msg, const std::tm& tm_time) override - { - msg.formatted << fmt::pad(tm_time.tm_min, 2, '0'); - } -}; - -// seconds 0-59 -class S_formatter :public flag_formatter -{ - void format(details::log_msg& msg, const std::tm& tm_time) override - { - msg.formatted << fmt::pad(tm_time.tm_sec, 2, '0'); - } -}; - -// milliseconds -class e_formatter :public flag_formatter -{ - void format(details::log_msg& msg, const std::tm&) override - { - auto duration = msg.time.time_since_epoch(); - auto millis = std::chrono::duration_cast(duration).count() % 1000; - msg.formatted << fmt::pad(static_cast(millis), 3, '0'); - } -}; - -// microseconds -class f_formatter :public flag_formatter -{ - void format(details::log_msg& msg, const std::tm&) override - { - auto duration = msg.time.time_since_epoch(); - auto micros = std::chrono::duration_cast(duration).count() % 1000000; - msg.formatted << fmt::pad(static_cast(micros), 6, '0'); - } -}; - -// nanoseconds -class F_formatter :public flag_formatter -{ - void format(details::log_msg& msg, const std::tm&) override - { - auto duration = msg.time.time_since_epoch(); - auto ns = std::chrono::duration_cast(duration).count() % 1000000000; - msg.formatted << fmt::pad(static_cast(ns), 9, '0'); - } -}; - -// AM/PM -class p_formatter :public flag_formatter -{ - void format(details::log_msg& msg, const std::tm& tm_time) override - { - msg.formatted << ampm(tm_time); - } -}; - - -// 12 hour clock 02:55:02 pm -class r_formatter :public flag_formatter -{ - void format(details::log_msg& msg, const std::tm& tm_time) override - { - pad_n_join(msg.formatted, to12h(tm_time), tm_time.tm_min, tm_time.tm_sec, ':') << ' ' << ampm(tm_time); - } -}; - -// 24-hour HH:MM time, equivalent to %H:%M -class R_formatter :public flag_formatter -{ - void format(details::log_msg& msg, const std::tm& tm_time) override - { - pad_n_join(msg.formatted, tm_time.tm_hour, tm_time.tm_min, ':'); - } -}; - -// ISO 8601 time format (HH:MM:SS), equivalent to %H:%M:%S -class T_formatter :public flag_formatter -{ - void format(details::log_msg& msg, const std::tm& tm_time) override - { - pad_n_join(msg.formatted, tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec, ':'); - } -}; - - -// ISO 8601 offset from UTC in timezone (+-HH:MM) -class z_formatter :public flag_formatter -{ -public: - const std::chrono::seconds cache_refresh = std::chrono::seconds(5); - - z_formatter() :_last_update(std::chrono::seconds(0)) {} - z_formatter(const z_formatter&) = delete; - z_formatter& operator=(const z_formatter&) = delete; - - void format(details::log_msg& msg, const std::tm& tm_time) override - { -#ifdef _WIN32 - int total_minutes = get_cached_offset(msg, tm_time); -#else - // No need to chache under gcc, - // it is very fast (already stored in tm.tm_gmtoff) - int total_minutes = os::utc_minutes_offset(tm_time); -#endif - - int h = total_minutes / 60; - int m = total_minutes % 60; - if (h >= 0) //minus sign will be printed anyway if negative - { - msg.formatted << '+'; - } - pad_n_join(msg.formatted, h, m, ':'); - } -private: - log_clock::time_point _last_update; - int _offset_minutes; - std::mutex _mutex; - - int get_cached_offset(const log_msg& msg, const std::tm& tm_time) - { - using namespace std::chrono; - std::lock_guard l(_mutex); - if (msg.time - _last_update >= cache_refresh) - { - _offset_minutes = os::utc_minutes_offset(tm_time); - _last_update = msg.time; - } - return _offset_minutes; - } -}; - - - -//Thread id -class t_formatter :public flag_formatter -{ - void format(details::log_msg& msg, const std::tm&) override - { - msg.formatted << msg.thread_id; - } -}; - - -class v_formatter :public flag_formatter -{ - void format(details::log_msg& msg, const std::tm&) override - { - msg.formatted << fmt::StringRef(msg.raw.data(), msg.raw.size()); - } -}; - -class ch_formatter :public flag_formatter -{ -public: - explicit ch_formatter(char ch) : _ch(ch) - {} - void format(details::log_msg& msg, const std::tm&) override - { - msg.formatted << _ch; - } -private: - char _ch; -}; - - -//aggregate user chars to display as is -class aggregate_formatter :public flag_formatter -{ -public: - aggregate_formatter() - {} - void add_ch(char ch) - { - _str += ch; - } - void format(details::log_msg& msg, const std::tm&) override - { - msg.formatted << _str; - } -private: - std::string _str; -}; - -// Full info formatter -// pattern: [%Y-%m-%d %H:%M:%S.%e] [%n] [%l] %v -class full_formatter :public flag_formatter -{ - void format(details::log_msg& msg, const std::tm& tm_time) override - { -#ifndef SPDLOG_NO_DATETIME - auto duration = msg.time.time_since_epoch(); - auto millis = std::chrono::duration_cast(duration).count() % 1000; - - /* Slower version(while still very fast - about 3.2 million lines/sec under 10 threads), - msg.formatted.write("[{:d}-{:02d}-{:02d} {:02d}:{:02d}:{:02d}.{:03d}] [{}] [{}] {} ", - tm_time.tm_year + 1900, - tm_time.tm_mon + 1, - tm_time.tm_mday, - tm_time.tm_hour, - tm_time.tm_min, - tm_time.tm_sec, - static_cast(millis), - msg.logger_name, - level::to_str(msg.level), - msg.raw.str());*/ - - - // Faster (albeit uglier) way to format the line (5.6 million lines/sec under 10 threads) - msg.formatted << '[' << static_cast(tm_time.tm_year + 1900) << '-' - << fmt::pad(static_cast(tm_time.tm_mon + 1), 2, '0') << '-' - << fmt::pad(static_cast(tm_time.tm_mday), 2, '0') << ' ' - << fmt::pad(static_cast(tm_time.tm_hour), 2, '0') << ':' - << fmt::pad(static_cast(tm_time.tm_min), 2, '0') << ':' - << fmt::pad(static_cast(tm_time.tm_sec), 2, '0') << '.' - << fmt::pad(static_cast(millis), 3, '0') << "] "; - -//no datetime needed -#else - (void)tm_time; -#endif - -#ifndef SPDLOG_NO_NAME - msg.formatted << '[' << msg.logger_name << "] "; -#endif - - msg.formatted << '[' << level::to_str(msg.level) << "] "; - msg.formatted << fmt::StringRef(msg.raw.data(), msg.raw.size()); - } -}; - -} -} -/////////////////////////////////////////////////////////////////////////////// -// pattern_formatter inline impl -/////////////////////////////////////////////////////////////////////////////// -inline spdlog::pattern_formatter::pattern_formatter(const std::string& pattern) -{ - compile_pattern(pattern); -} - -inline void spdlog::pattern_formatter::compile_pattern(const std::string& pattern) -{ - auto end = pattern.end(); - std::unique_ptr user_chars; - for (auto it = pattern.begin(); it != end; ++it) - { - if (*it == '%') - { - if (user_chars) //append user chars found so far - _formatters.push_back(std::move(user_chars)); - - if (++it != end) - handle_flag(*it); - else - break; - } - else // chars not following the % sign should be displayed as is - { - if (!user_chars) - user_chars = std::unique_ptr(new details::aggregate_formatter()); - user_chars->add_ch(*it); - } - } - if (user_chars) //append raw chars found so far - { - _formatters.push_back(std::move(user_chars)); - } - -} -inline void spdlog::pattern_formatter::handle_flag(char flag) -{ - switch (flag) - { - // logger name - case 'n': - _formatters.push_back(std::unique_ptr(new details::name_formatter())); - break; - - case 'l': - _formatters.push_back(std::unique_ptr(new details::level_formatter())); - break; - - case 'L': - _formatters.push_back(std::unique_ptr(new details::short_level_formatter())); - break; - - case('t') : - _formatters.push_back(std::unique_ptr(new details::t_formatter())); - break; - - case('v') : - _formatters.push_back(std::unique_ptr(new details::v_formatter())); - break; - - case('a') : - _formatters.push_back(std::unique_ptr(new details::a_formatter())); - break; - - case('A') : - _formatters.push_back(std::unique_ptr(new details::A_formatter())); - break; - - case('b') : - case('h') : - _formatters.push_back(std::unique_ptr(new details::b_formatter())); - break; - - case('B') : - _formatters.push_back(std::unique_ptr(new details::B_formatter())); - break; - case('c') : - _formatters.push_back(std::unique_ptr(new details::c_formatter())); - break; - - case('C') : - _formatters.push_back(std::unique_ptr(new details::C_formatter())); - break; - - case('Y') : - _formatters.push_back(std::unique_ptr(new details::Y_formatter())); - break; - - case('D') : - case('x') : - - _formatters.push_back(std::unique_ptr(new details::D_formatter())); - break; - - case('m') : - _formatters.push_back(std::unique_ptr(new details::m_formatter())); - break; - - case('d') : - _formatters.push_back(std::unique_ptr(new details::d_formatter())); - break; - - case('H') : - _formatters.push_back(std::unique_ptr(new details::H_formatter())); - break; - - case('I') : - _formatters.push_back(std::unique_ptr(new details::I_formatter())); - break; - - case('M') : - _formatters.push_back(std::unique_ptr(new details::M_formatter())); - break; - - case('S') : - _formatters.push_back(std::unique_ptr(new details::S_formatter())); - break; - - case('e') : - _formatters.push_back(std::unique_ptr(new details::e_formatter())); - break; - - case('f') : - _formatters.push_back(std::unique_ptr(new details::f_formatter())); - break; - case('F') : - _formatters.push_back(std::unique_ptr(new details::F_formatter())); - break; - - case('p') : - _formatters.push_back(std::unique_ptr(new details::p_formatter())); - break; - - case('r') : - _formatters.push_back(std::unique_ptr(new details::r_formatter())); - break; - - case('R') : - _formatters.push_back(std::unique_ptr(new details::R_formatter())); - break; - - case('T') : - case('X') : - _formatters.push_back(std::unique_ptr(new details::T_formatter())); - break; - - case('z') : - _formatters.push_back(std::unique_ptr(new details::z_formatter())); - break; - - case ('+'): - _formatters.push_back(std::unique_ptr(new details::full_formatter())); - break; - - default: //Unkown flag appears as is - _formatters.push_back(std::unique_ptr(new details::ch_formatter('%'))); - _formatters.push_back(std::unique_ptr(new details::ch_formatter(flag))); - break; - } -} - - -inline void spdlog::pattern_formatter::format(details::log_msg& msg) -{ - try - { - auto tm_time = details::os::localtime(log_clock::to_time_t(msg.time)); - for (auto &f : _formatters) - { - f->format(msg, tm_time); - } - //write eol - msg.formatted << details::os::eol(); - } - catch(const fmt::FormatError& e) - { - throw spdlog_ex(fmt::format("formatting error while processing format string: {}", e.what())); - } -} diff --git a/cameradar_standalone/include/spdlog/details/registry.h b/cameradar_standalone/include/spdlog/details/registry.h deleted file mode 100644 index a26db79..0000000 --- a/cameradar_standalone/include/spdlog/details/registry.h +++ /dev/null @@ -1,162 +0,0 @@ -// -// Copyright(c) 2015 Gabi Melman. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) -// - -#pragma once - -// Loggers registy of unique name->logger pointer -// An attempt to create a logger with an already existing name will be ignored -// If user requests a non existing logger, nullptr will be returned -// This class is thread safe - -#include -#include -#include -#include - -#include "./null_mutex.h" -#include "../logger.h" -#include "../async_logger.h" -#include "../common.h" - -namespace spdlog -{ -namespace details -{ -template class registry_t -{ -public: - - void register_logger(std::shared_ptr logger) - { - std::lock_guard lock(_mutex); - register_logger_impl(logger); - } - - - std::shared_ptr get(const std::string& logger_name) - { - std::lock_guard lock(_mutex); - auto found = _loggers.find(logger_name); - return found == _loggers.end() ? nullptr : found->second; - } - - template - std::shared_ptr create(const std::string& logger_name, const It& sinks_begin, const It& sinks_end) - { - - std::shared_ptr new_logger; - - std::lock_guard lock(_mutex); - - - if (_async_mode) - new_logger = std::make_shared(logger_name, sinks_begin, sinks_end, _async_q_size, _overflow_policy, _worker_warmup_cb, _flush_interval_ms); - else - new_logger = std::make_shared(logger_name, sinks_begin, sinks_end); - - if (_formatter) - new_logger->set_formatter(_formatter); - - new_logger->set_level(_level); - register_logger_impl(new_logger); - return new_logger; - } - - void drop(const std::string& logger_name) - { - std::lock_guard lock(_mutex); - _loggers.erase(logger_name); - } - - void drop_all() - { - std::lock_guard lock(_mutex); - _loggers.clear(); - } - std::shared_ptr create(const std::string& logger_name, sinks_init_list sinks) - { - return create(logger_name, sinks.begin(), sinks.end()); - } - - std::shared_ptr create(const std::string& logger_name, sink_ptr sink) - { - return create(logger_name, { sink }); - } - - - void formatter(formatter_ptr f) - { - std::lock_guard lock(_mutex); - _formatter = f; - for (auto& l : _loggers) - l.second->set_formatter(_formatter); - } - - void set_pattern(const std::string& pattern) - { - std::lock_guard lock(_mutex); - _formatter = std::make_shared(pattern); - for (auto& l : _loggers) - l.second->set_formatter(_formatter); - } - - void set_level(level::level_enum log_level) - { - std::lock_guard lock(_mutex); - for (auto& l : _loggers) - l.second->set_level(log_level); - _level = log_level; - } - - void set_async_mode(size_t q_size, const async_overflow_policy overflow_policy, const std::function& worker_warmup_cb, const std::chrono::milliseconds& flush_interval_ms) - { - std::lock_guard lock(_mutex); - _async_mode = true; - _async_q_size = q_size; - _overflow_policy = overflow_policy; - _worker_warmup_cb = worker_warmup_cb; - _flush_interval_ms = flush_interval_ms; - } - - void set_sync_mode() - { - std::lock_guard lock(_mutex); - _async_mode = false; - } - - static registry_t& instance() - { - static registry_t s_instance; - return s_instance; - } - -private: - void register_logger_impl(std::shared_ptr logger) - { - auto logger_name = logger->name(); - if (_loggers.find(logger_name) != std::end(_loggers)) - throw spdlog_ex("logger with name " + logger_name + " already exists"); - _loggers[logger->name()] = logger; - } - registry_t() {} - registry_t(const registry_t&) = delete; - registry_t& operator=(const registry_t&) = delete; - Mutex _mutex; - std::unordered_map > _loggers; - formatter_ptr _formatter; - level::level_enum _level = level::info; - bool _async_mode = false; - size_t _async_q_size = 0; - async_overflow_policy _overflow_policy = async_overflow_policy::block_retry; - std::function _worker_warmup_cb = nullptr; - std::chrono::milliseconds _flush_interval_ms; -}; -#ifdef SPDLOG_NO_REGISTRY_MUTEX -typedef registry_t registry; -#else -typedef registry_t registry; -#endif -} -} diff --git a/cameradar_standalone/include/spdlog/details/spdlog_impl.h b/cameradar_standalone/include/spdlog/details/spdlog_impl.h deleted file mode 100644 index 85a7dc1..0000000 --- a/cameradar_standalone/include/spdlog/details/spdlog_impl.h +++ /dev/null @@ -1,135 +0,0 @@ -// -// Copyright(c) 2015 Gabi Melman. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) -// - -#pragma once - -// -// Global registry functions -// -#include "registry.h" -#include "../sinks/file_sinks.h" -#include "../sinks/stdout_sinks.h" -#include "../sinks/syslog_sink.h" - -inline void spdlog::register_logger(std::shared_ptr logger) -{ - return details::registry::instance().register_logger(logger); -} - -inline std::shared_ptr spdlog::get(const std::string& name) -{ - return details::registry::instance().get(name); -} - -inline void spdlog::drop(const std::string &name) -{ - details::registry::instance().drop(name); -} - -// Create multi/single threaded rotating file logger -inline std::shared_ptr spdlog::rotating_logger_mt(const std::string& logger_name, const std::string& filename, size_t max_file_size, size_t max_files, bool force_flush) -{ - return create(logger_name, filename, "txt", max_file_size, max_files, force_flush); -} - -inline std::shared_ptr spdlog::rotating_logger_st(const std::string& logger_name, const std::string& filename, size_t max_file_size, size_t max_files, bool force_flush) -{ - return create(logger_name, filename, "txt", max_file_size, max_files, force_flush); -} - -// Create file logger which creates new file at midnight): -inline std::shared_ptr spdlog::daily_logger_mt(const std::string& logger_name, const std::string& filename, int hour, int minute, bool force_flush) -{ - return create(logger_name, filename, "txt", hour, minute, force_flush); -} -inline std::shared_ptr spdlog::daily_logger_st(const std::string& logger_name, const std::string& filename, int hour, int minute, bool force_flush) -{ - return create(logger_name, filename, "txt", hour, minute, force_flush); -} - - -// Create stdout/stderr loggers -inline std::shared_ptr spdlog::stdout_logger_mt(const std::string& logger_name) -{ - return details::registry::instance().create(logger_name, spdlog::sinks::stdout_sink_mt::instance()); -} - -inline std::shared_ptr spdlog::stdout_logger_st(const std::string& logger_name) -{ - return details::registry::instance().create(logger_name, spdlog::sinks::stdout_sink_st::instance()); -} - -inline std::shared_ptr spdlog::stderr_logger_mt(const std::string& logger_name) -{ - return details::registry::instance().create(logger_name, spdlog::sinks::stderr_sink_mt::instance()); -} - -inline std::shared_ptr spdlog::stderr_logger_st(const std::string& logger_name) -{ - return details::registry::instance().create(logger_name, spdlog::sinks::stderr_sink_st::instance()); -} - -#ifdef __linux__ -// Create syslog logger -inline std::shared_ptr spdlog::syslog_logger(const std::string& logger_name, const std::string& syslog_ident, int syslog_option) -{ - return create(logger_name, syslog_ident, syslog_option); -} -#endif - - -//Create logger with multiple sinks - -inline std::shared_ptr spdlog::create(const std::string& logger_name, spdlog::sinks_init_list sinks) -{ - return details::registry::instance().create(logger_name, sinks); -} - - -template -inline std::shared_ptr spdlog::create(const std::string& logger_name, Args... args) -{ - sink_ptr sink = std::make_shared(args...); - return details::registry::instance().create(logger_name, { sink }); -} - - -template -inline std::shared_ptr spdlog::create(const std::string& logger_name, const It& sinks_begin, const It& sinks_end) -{ - return details::registry::instance().create(logger_name, sinks_begin, sinks_end); -} - -inline void spdlog::set_formatter(spdlog::formatter_ptr f) -{ - details::registry::instance().formatter(f); -} - -inline void spdlog::set_pattern(const std::string& format_string) -{ - return details::registry::instance().set_pattern(format_string); -} - -inline void spdlog::set_level(level::level_enum log_level) -{ - return details::registry::instance().set_level(log_level); -} - - -inline void spdlog::set_async_mode(size_t queue_size, const async_overflow_policy overflow_policy, const std::function& worker_warmup_cb, const std::chrono::milliseconds& flush_interval_ms) -{ - details::registry::instance().set_async_mode(queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms); -} - -inline void spdlog::set_sync_mode() -{ - details::registry::instance().set_sync_mode(); -} - -inline void spdlog::drop_all() -{ - details::registry::instance().drop_all(); -} - diff --git a/cameradar_standalone/include/spdlog/formatter.h b/cameradar_standalone/include/spdlog/formatter.h deleted file mode 100644 index 1d12686..0000000 --- a/cameradar_standalone/include/spdlog/formatter.h +++ /dev/null @@ -1,35 +0,0 @@ -// -// Copyright(c) 2015 Gabi Melman. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) -// - -#pragma once - -#include "details/log_msg.h" -namespace spdlog { -namespace details { -class flag_formatter; -} - -class formatter { -public: - virtual ~formatter() {} - virtual void format(details::log_msg& msg) = 0; -}; - -class pattern_formatter : public formatter { -public: - explicit pattern_formatter(const std::string& pattern); - pattern_formatter(const pattern_formatter&) = delete; - pattern_formatter& operator=(const pattern_formatter&) = delete; - void format(details::log_msg& msg) override; - -private: - const std::string _pattern; - std::vector> _formatters; - void handle_flag(char flag); - void compile_pattern(const std::string& pattern); -}; -} - -#include "details/pattern_formatter_impl.h" diff --git a/cameradar_standalone/include/spdlog/logger.h b/cameradar_standalone/include/spdlog/logger.h deleted file mode 100644 index baa1386..0000000 --- a/cameradar_standalone/include/spdlog/logger.h +++ /dev/null @@ -1,123 +0,0 @@ -// -// Copyright(c) 2015 Gabi Melman. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) -// - -#pragma once - -// Thread safe logger -// Has name, log level, vector of std::shared sink pointers and formatter -// Upon each log write the logger: -// 1. Checks if its log level is enough to log the message -// 2. Format the message using the formatter function -// 3. Pass the formatted message to its sinks to performa the actual logging - -#include -#include -#include "sinks/base_sink.h" -#include "common.h" - -namespace spdlog { - -namespace details { -class line_logger; -} - -class logger { -public: - logger(const std::string& logger_name, sink_ptr single_sink); - logger(const std::string& name, sinks_init_list); - template - logger(const std::string& name, const It& begin, const It& end); - - virtual ~logger(); - logger(const logger&) = delete; - logger& operator=(const logger&) = delete; - - void set_level(level::level_enum); - level::level_enum level() const; - - const std::string& name() const; - bool should_log(level::level_enum) const; - - // logger.info(cppformat_string, arg1, arg2, arg3, ...) call style - template - details::line_logger trace(const char* fmt, const Args&... args); - template - details::line_logger debug(const char* fmt, const Args&... args); - template - details::line_logger info(const char* fmt, const Args&... args); - template - details::line_logger notice(const char* fmt, const Args&... args); - template - details::line_logger warn(const char* fmt, const Args&... args); - template - details::line_logger error(const char* fmt, const Args&... args); - template - details::line_logger critical(const char* fmt, const Args&... args); - template - details::line_logger alert(const char* fmt, const Args&... args); - template - details::line_logger emerg(const char* fmt, const Args&... args); - - // logger.info(msg) << ".." call style - template - details::line_logger trace(const T&); - template - details::line_logger debug(const T&); - template - details::line_logger info(const T&); - template - details::line_logger notice(const T&); - template - details::line_logger warn(const T&); - template - details::line_logger error(const T&); - template - details::line_logger critical(const T&); - template - details::line_logger alert(const T&); - template - details::line_logger emerg(const T&); - - // logger.info() << ".." call style - details::line_logger trace(); - details::line_logger debug(); - details::line_logger info(); - details::line_logger notice(); - details::line_logger warn(); - details::line_logger error(); - details::line_logger critical(); - details::line_logger alert(); - details::line_logger emerg(); - - // Create log message with the given level, no matter what is the actual logger's level - template - details::line_logger force_log(level::level_enum lvl, const char* fmt, const Args&... args); - - // Set the format of the log messages from this logger - void set_pattern(const std::string&); - void set_formatter(formatter_ptr); - - virtual void flush(); - -protected: - virtual void _log_msg(details::log_msg&); - virtual void _set_pattern(const std::string&); - virtual void _set_formatter(formatter_ptr); - details::line_logger _log_if_enabled(level::level_enum lvl); - template - details::line_logger - _log_if_enabled(level::level_enum lvl, const char* fmt, const Args&... args); - template - inline details::line_logger _log_if_enabled(level::level_enum lvl, const T& msg); - - friend details::line_logger; - std::string _name; - std::vector _sinks; - formatter_ptr _formatter; - std::atomic_int _level; -}; -} - -#include "./details/logger_impl.h" diff --git a/cameradar_standalone/include/spdlog/sinks/android_sink.h b/cameradar_standalone/include/spdlog/sinks/android_sink.h deleted file mode 100644 index 75e1cd0..0000000 --- a/cameradar_standalone/include/spdlog/sinks/android_sink.h +++ /dev/null @@ -1,67 +0,0 @@ -// -// Copyright(c) 2015 Gabi Melman. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) -// - -#pragma once - -#if defined(__ANDROID__) - -#include -#include "base_sink.h" -#include "../details/null_mutex.h" - -#include - -namespace spdlog { -namespace sinks { -/* -* Android sink (logging using __android_log_write) -*/ -template -class base_android_sink : public base_sink { -public: - explicit base_android_sink(std::string tag = "spdlog") : _tag(tag) {} - - void - flush() override {} - -protected: - void - _sink_it(const details::log_msg& msg) override { - const android_LogPriority priority = convert_to_android(msg.level); - const int expected_size = msg.formatted.size(); - const int size = __android_log_write(priority, _tag.c_str(), msg.formatted.c_str()); - if (size > expected_size) { - // Will write a little bit more than original message - } else { - throw spdlog_ex("Send to Android logcat failed"); - } - } - -private: - static android_LogPriority - convert_to_android(spdlog::level::level_enum level) { - switch (level) { - case spdlog::level::trace: return ANDROID_LOG_VERBOSE; - case spdlog::level::debug: return ANDROID_LOG_DEBUG; - case spdlog::level::info: return ANDROID_LOG_INFO; - case spdlog::level::notice: return ANDROID_LOG_INFO; - case spdlog::level::warn: return ANDROID_LOG_WARN; - case spdlog::level::err: return ANDROID_LOG_ERROR; - case spdlog::level::critical: return ANDROID_LOG_FATAL; - case spdlog::level::alert: return ANDROID_LOG_FATAL; - case spdlog::level::emerg: return ANDROID_LOG_FATAL; - default: throw spdlog_ex("Incorrect level value"); - } - } - - std::string _tag; -}; - -typedef base_android_sink android_sink_mt; -typedef base_android_sink android_sink_st; -} -} - -#endif diff --git a/cameradar_standalone/include/spdlog/sinks/base_sink.h b/cameradar_standalone/include/spdlog/sinks/base_sink.h deleted file mode 100644 index 16f34e1..0000000 --- a/cameradar_standalone/include/spdlog/sinks/base_sink.h +++ /dev/null @@ -1,43 +0,0 @@ -// -// Copyright(c) 2015 Gabi Melman. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) -// - -#pragma once -// -// base sink templated over a mutex (either dummy or realy) -// concrete implementation should only overrid the _sink_it method. -// all locking is taken care of here so no locking needed by the implementors.. -// - -#include -#include -#include -#include "./sink.h" -#include "../formatter.h" -#include "../common.h" -#include "../details/log_msg.h" - -namespace spdlog { -namespace sinks { -template -class base_sink : public sink { -public: - base_sink() : _mutex() {} - virtual ~base_sink() = default; - - base_sink(const base_sink&) = delete; - base_sink& operator=(const base_sink&) = delete; - - void - log(const details::log_msg& msg) override { - std::lock_guard lock(_mutex); - _sink_it(msg); - } - -protected: - virtual void _sink_it(const details::log_msg& msg) = 0; - Mutex _mutex; -}; -} -} diff --git a/cameradar_standalone/include/spdlog/sinks/dist_sink.h b/cameradar_standalone/include/spdlog/sinks/dist_sink.h deleted file mode 100644 index 80099fc..0000000 --- a/cameradar_standalone/include/spdlog/sinks/dist_sink.h +++ /dev/null @@ -1,62 +0,0 @@ -// -// Copyright (c) 2015 David Schury, Gabi Melman -// Distributed under the MIT License (http://opensource.org/licenses/MIT) -// - -#pragma once - -#include -#include -#include -#include - -#include "../details/log_msg.h" -#include "../details/null_mutex.h" -#include "./base_sink.h" -#include "./sink.h" - -namespace spdlog { -namespace sinks { -template -class dist_sink : public base_sink { -public: - explicit dist_sink() : _sinks() {} - dist_sink(const dist_sink&) = delete; - dist_sink& operator=(const dist_sink&) = delete; - virtual ~dist_sink() = default; - -protected: - void - _sink_it(const details::log_msg& msg) override { - for (auto iter = _sinks.begin(); iter != _sinks.end(); iter++) (*iter)->log(msg); - } - - std::vector> _sinks; - -public: - void - flush() override { - std::lock_guard lock(base_sink::_mutex); - for (auto iter = _sinks.begin(); iter != _sinks.end(); iter++) (*iter)->flush(); - } - - void - add_sink(std::shared_ptr sink) { - std::lock_guard lock(base_sink::_mutex); - if (sink && _sinks.end() == std::find(_sinks.begin(), _sinks.end(), sink)) { - _sinks.push_back(sink); - } - } - - void - remove_sink(std::shared_ptr sink) { - std::lock_guard lock(base_sink::_mutex); - auto pos = std::find(_sinks.begin(), _sinks.end(), sink); - if (pos != _sinks.end()) { _sinks.erase(pos); } - } -}; - -typedef dist_sink dist_sink_mt; -typedef dist_sink dist_sink_st; -} -} diff --git a/cameradar_standalone/include/spdlog/sinks/file_sinks.h b/cameradar_standalone/include/spdlog/sinks/file_sinks.h deleted file mode 100644 index 9301594..0000000 --- a/cameradar_standalone/include/spdlog/sinks/file_sinks.h +++ /dev/null @@ -1,210 +0,0 @@ -// -// Copyright(c) 2015 Gabi Melman. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) -// - -#pragma once - -#include -#include "base_sink.h" -#include "../details/null_mutex.h" -#include "../details/file_helper.h" -#include "../details/format.h" - -namespace spdlog { -namespace sinks { -/* -* Trivial file sink with single file as target -*/ -template -class simple_file_sink : public base_sink { -public: - explicit simple_file_sink(const std::string& filename, bool force_flush = false) - : _file_helper(force_flush) { - _file_helper.open(filename); - } - void - flush() override { - _file_helper.flush(); - } - -protected: - void - _sink_it(const details::log_msg& msg) override { - _file_helper.write(msg); - } - -private: - details::file_helper _file_helper; -}; - -typedef simple_file_sink simple_file_sink_mt; -typedef simple_file_sink simple_file_sink_st; - -/* -* Rotating file sink based on size -*/ -template -class rotating_file_sink : public base_sink { -public: - rotating_file_sink(const std::string& base_filename, - const std::string& extension, - std::size_t max_size, - std::size_t max_files, - bool force_flush = false) - : _base_filename(base_filename) - , _extension(extension) - , _max_size(max_size) - , _max_files(max_files) - , _current_size(0) - , _file_helper(force_flush) { - _file_helper.open(calc_filename(_base_filename, 0, _extension)); - _current_size = _file_helper.size(); // expensive. called only once - } - - void - flush() override { - _file_helper.flush(); - } - -protected: - void - _sink_it(const details::log_msg& msg) override { - _current_size += msg.formatted.size(); - if (_current_size > _max_size) { - _rotate(); - _current_size = msg.formatted.size(); - } - _file_helper.write(msg); - } - -private: - static std::string - calc_filename(const std::string& filename, std::size_t index, const std::string& extension) { - fmt::MemoryWriter w; - if (index) - w.write("{}.{}.{}", filename, index, extension); - else - w.write("{}.{}", filename, extension); - return w.str(); - } - - // Rotate files: - // log.txt -> log.1.txt - // log.1.txt -> log2.txt - // log.2.txt -> log3.txt - // log.3.txt -> delete - - void - _rotate() { - _file_helper.close(); - for (auto i = _max_files; i > 0; --i) { - std::string src = calc_filename(_base_filename, i - 1, _extension); - std::string target = calc_filename(_base_filename, i, _extension); - - if (details::file_helper::file_exists(target)) { - if (std::remove(target.c_str()) != 0) { - throw spdlog_ex("rotating_file_sink: failed removing " + target); - } - } - if (details::file_helper::file_exists(src) && - std::rename(src.c_str(), target.c_str())) { - throw spdlog_ex("rotating_file_sink: failed renaming " + src + " to " + target); - } - } - _file_helper.reopen(true); - } - std::string _base_filename; - std::string _extension; - std::size_t _max_size; - std::size_t _max_files; - std::size_t _current_size; - details::file_helper _file_helper; -}; - -typedef rotating_file_sink rotating_file_sink_mt; -typedef rotating_file_sink rotating_file_sink_st; - -/* -* Rotating file sink based on date. rotates at midnight -*/ -template -class daily_file_sink : public base_sink { -public: - // create daily file sink which rotates on given time - daily_file_sink(const std::string& base_filename, - const std::string& extension, - int rotation_hour, - int rotation_minute, - bool force_flush = false) - : _base_filename(base_filename) - , _extension(extension) - , _rotation_h(rotation_hour) - , _rotation_m(rotation_minute) - , _file_helper(force_flush) { - if (rotation_hour < 0 || rotation_hour > 23 || rotation_minute < 0 || rotation_minute > 59) - throw spdlog_ex("daily_file_sink: Invalid rotation time in ctor"); - _rotation_tp = _next_rotation_tp(); - _file_helper.open(calc_filename(_base_filename, _extension)); - } - - void - flush() override { - _file_helper.flush(); - } - -protected: - void - _sink_it(const details::log_msg& msg) override { - if (std::chrono::system_clock::now() >= _rotation_tp) { - _file_helper.open(calc_filename(_base_filename, _extension)); - _rotation_tp = _next_rotation_tp(); - } - _file_helper.write(msg); - } - -private: - std::chrono::system_clock::time_point - _next_rotation_tp() { - using namespace std::chrono; - auto now = system_clock::now(); - time_t tnow = std::chrono::system_clock::to_time_t(now); - tm date = spdlog::details::os::localtime(tnow); - date.tm_hour = _rotation_h; - date.tm_min = _rotation_m; - date.tm_sec = 0; - auto rotation_time = std::chrono::system_clock::from_time_t(std::mktime(&date)); - if (rotation_time > now) - return rotation_time; - else - return system_clock::time_point(rotation_time + hours(24)); - } - - // Create filename for the form basename.YYYY-MM-DD.extension - static std::string - calc_filename(const std::string& basename, const std::string& extension) { - std::tm tm = spdlog::details::os::localtime(); - fmt::MemoryWriter w; - w.write("{}_{:04d}-{:02d}-{:02d}_{:02d}-{:02d}.{}", - basename, - tm.tm_year + 1900, - tm.tm_mon + 1, - tm.tm_mday, - tm.tm_hour, - tm.tm_min, - extension); - return w.str(); - } - - std::string _base_filename; - std::string _extension; - int _rotation_h; - int _rotation_m; - std::chrono::system_clock::time_point _rotation_tp; - details::file_helper _file_helper; -}; - -typedef daily_file_sink daily_file_sink_mt; -typedef daily_file_sink daily_file_sink_st; -} -} diff --git a/cameradar_standalone/include/spdlog/sinks/null_sink.h b/cameradar_standalone/include/spdlog/sinks/null_sink.h deleted file mode 100644 index 89fba7f..0000000 --- a/cameradar_standalone/include/spdlog/sinks/null_sink.h +++ /dev/null @@ -1,26 +0,0 @@ -// -// Copyright(c) 2015 Gabi Melman. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) -// - -#pragma once -#include -#include "./base_sink.h" -#include "../details/null_mutex.h" - -namespace spdlog { -namespace sinks { - -template -class null_sink : public base_sink { -protected: - void - _sink_it(const details::log_msg&) override {} - - void - flush() override {} -}; -typedef null_sink null_sink_st; -typedef null_sink null_sink_mt; -} -} diff --git a/cameradar_standalone/include/spdlog/sinks/ostream_sink.h b/cameradar_standalone/include/spdlog/sinks/ostream_sink.h deleted file mode 100644 index ba3119b..0000000 --- a/cameradar_standalone/include/spdlog/sinks/ostream_sink.h +++ /dev/null @@ -1,45 +0,0 @@ -// -// Copyright(c) 2015 Gabi Melman. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) -// - -#pragma once - -#include -#include -#include - -#include "../details/null_mutex.h" -#include "./base_sink.h" - -namespace spdlog { -namespace sinks { -template -class ostream_sink : public base_sink { -public: - explicit ostream_sink(std::ostream& os, bool force_flush = false) - : _ostream(os), _force_flush(force_flush) {} - ostream_sink(const ostream_sink&) = delete; - ostream_sink& operator=(const ostream_sink&) = delete; - virtual ~ostream_sink() = default; - -protected: - void - _sink_it(const details::log_msg& msg) override { - _ostream.write(msg.formatted.data(), msg.formatted.size()); - if (_force_flush) _ostream.flush(); - } - - void - flush() override { - _ostream.flush(); - } - - std::ostream& _ostream; - bool _force_flush; -}; - -typedef ostream_sink ostream_sink_mt; -typedef ostream_sink ostream_sink_st; -} -} diff --git a/cameradar_standalone/include/spdlog/sinks/sink.h b/cameradar_standalone/include/spdlog/sinks/sink.h deleted file mode 100644 index 7c562a3..0000000 --- a/cameradar_standalone/include/spdlog/sinks/sink.h +++ /dev/null @@ -1,19 +0,0 @@ -// -// Copyright(c) 2015 Gabi Melman. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) -// - -#pragma once - -#include "../details/log_msg.h" - -namespace spdlog { -namespace sinks { -class sink { -public: - virtual ~sink() {} - virtual void log(const details::log_msg& msg) = 0; - virtual void flush() = 0; -}; -} -} diff --git a/cameradar_standalone/include/spdlog/sinks/stdout_sinks.h b/cameradar_standalone/include/spdlog/sinks/stdout_sinks.h deleted file mode 100644 index c9f6f8d..0000000 --- a/cameradar_standalone/include/spdlog/sinks/stdout_sinks.h +++ /dev/null @@ -1,48 +0,0 @@ -// -// Copyright(c) 2015 Gabi Melman. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) -// - -#pragma once - -#include -#include -#include "./ostream_sink.h" -#include "../details/null_mutex.h" - -namespace spdlog { -namespace sinks { - -template -class stdout_sink : public ostream_sink { - using MyType = stdout_sink; - -public: - stdout_sink() : ostream_sink(std::cout, true) {} - static std::shared_ptr - instance() { - static std::shared_ptr instance = std::make_shared(); - return instance; - } -}; - -typedef stdout_sink stdout_sink_st; -typedef stdout_sink stdout_sink_mt; - -template -class stderr_sink : public ostream_sink { - using MyType = stderr_sink; - -public: - stderr_sink() : ostream_sink(std::cerr, true) {} - static std::shared_ptr - instance() { - static std::shared_ptr instance = std::make_shared(); - return instance; - } -}; - -typedef stderr_sink stderr_sink_mt; -typedef stderr_sink stderr_sink_st; -} -} diff --git a/cameradar_standalone/include/spdlog/sinks/syslog_sink.h b/cameradar_standalone/include/spdlog/sinks/syslog_sink.h deleted file mode 100644 index 8f84c59..0000000 --- a/cameradar_standalone/include/spdlog/sinks/syslog_sink.h +++ /dev/null @@ -1,76 +0,0 @@ -// -// Copyright(c) 2015 Gabi Melman. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) -// - -#pragma once - -#ifdef __linux__ - -#include -#include -#include - -#include "./sink.h" -#include "../common.h" -#include "../details/log_msg.h" - -namespace spdlog { -namespace sinks { -/** - * Sink that write to syslog using the `syscall()` library call. - * - * Locking is not needed, as `syslog()` itself is thread-safe. - */ -class syslog_sink : public sink { -public: - // - syslog_sink(const std::string& ident = "", - int syslog_option = 0, - int syslog_facility = LOG_USER) - : _ident(ident) { - _priorities[static_cast(level::trace)] = LOG_DEBUG; - _priorities[static_cast(level::debug)] = LOG_DEBUG; - _priorities[static_cast(level::info)] = LOG_INFO; - _priorities[static_cast(level::notice)] = LOG_NOTICE; - _priorities[static_cast(level::warn)] = LOG_WARNING; - _priorities[static_cast(level::err)] = LOG_ERR; - _priorities[static_cast(level::critical)] = LOG_CRIT; - _priorities[static_cast(level::alert)] = LOG_ALERT; - _priorities[static_cast(level::emerg)] = LOG_EMERG; - _priorities[static_cast(level::off)] = LOG_INFO; - - // set ident to be program name if empty - ::openlog(_ident.empty() ? nullptr : _ident.c_str(), syslog_option, syslog_facility); - } - ~syslog_sink() { ::closelog(); } - - syslog_sink(const syslog_sink&) = delete; - syslog_sink& operator=(const syslog_sink&) = delete; - - void - log(const details::log_msg& msg) override { - ::syslog(syslog_prio_from_level(msg), "%s", msg.raw.str().c_str()); - } - - void - flush() override {} - -private: - std::array _priorities; - // must store the ident because the man says openlog might use the pointer as is and not a - // string copy - const std::string _ident; - - // - // Simply maps spdlog's log level to syslog priority level. - // - int - syslog_prio_from_level(const details::log_msg& msg) const { - return _priorities[static_cast(msg.level)]; - } -}; -} -} - -#endif diff --git a/cameradar_standalone/include/spdlog/spdlog.h b/cameradar_standalone/include/spdlog/spdlog.h deleted file mode 100644 index a05890f..0000000 --- a/cameradar_standalone/include/spdlog/spdlog.h +++ /dev/null @@ -1,151 +0,0 @@ -// -// Copyright(c) 2015 Gabi Melman. -// Distributed under the MIT License (http://opensource.org/licenses/MIT) -// - -// spdlog main header file. -// see example.cpp for usage example - -#pragma once - -#include "common.h" -#include "logger.h" - -namespace spdlog { -// Return an existing logger or nullptr if a logger with such name doesn't exist. -// Examples: -// -// spdlog::get("mylog")->info("Hello"); -// auto logger = spdlog::get("mylog"); -// logger.info("This is another message" , x, y, z); -// logger.info() << "This is another message" << x << y << z; -std::shared_ptr get(const std::string& name); - -// -// Set global formatting -// example: spdlog::set_pattern("%Y-%m-%d %H:%M:%S.%e %l : %v"); -// -void set_pattern(const std::string& format_string); -void set_formatter(formatter_ptr f); - -// -// Set global logging level for -// -void set_level(level::level_enum log_level); - -// -// Turn on async mode (off by default) and set the queue size for each async_logger. -// effective only for loggers created after this call. -// queue_size: size of queue (must be power of 2): -// Each logger will pre-allocate a dedicated queue with queue_size entries upon construction. -// -// async_overflow_policy (optional, block_retry by default): -// async_overflow_policy::block_retry - if queue is full, block until queue has room for the new -// log entry. -// async_overflow_policy::discard_log_msg - never block and discard any new messages when queue -// overflows. -// -// worker_warmup_cb (optional): -// callback function that will be called in worker thread upon start (can be used to init stuff -// like thread affinity) -// -void set_async_mode( - size_t queue_size, - const async_overflow_policy overflow_policy = async_overflow_policy::block_retry, - const std::function& worker_warmup_cb = nullptr, - const std::chrono::milliseconds& flush_interval_ms = std::chrono::milliseconds::zero()); - -// Turn off async mode -void set_sync_mode(); - -// -// Create and register multi/single threaded rotating file logger -// -std::shared_ptr rotating_logger_mt(const std::string& logger_name, - const std::string& filenameB, - size_t max_file_size, - size_t max_files, - bool force_flush = false); -std::shared_ptr rotating_logger_st(const std::string& logger_name, - const std::string& filename, - size_t max_file_size, - size_t max_files, - bool force_flush = false); - -// -// Create file logger which creates new file on the given time (default in midnight): -// -std::shared_ptr daily_logger_mt(const std::string& logger_name, - const std::string& filename, - int hour = 0, - int minute = 0, - bool force_flush = false); -std::shared_ptr daily_logger_st(const std::string& logger_name, - const std::string& filename, - int hour = 0, - int minute = 0, - bool force_flush = false); - -// -// Create and register stdout/stderr loggers -// -std::shared_ptr stdout_logger_mt(const std::string& logger_name); -std::shared_ptr stdout_logger_st(const std::string& logger_name); -std::shared_ptr stderr_logger_mt(const std::string& logger_name); -std::shared_ptr stderr_logger_st(const std::string& logger_name); - -// -// Create and register a syslog logger -// -#ifdef __linux__ -std::shared_ptr -syslog_logger(const std::string& logger_name, const std::string& ident = "", int syslog_option = 0); -#endif - -// Create and register a logger with multiple sinks -std::shared_ptr create(const std::string& logger_name, sinks_init_list sinks); -template -std::shared_ptr -create(const std::string& logger_name, const It& sinks_begin, const It& sinks_end); - -// Create and register a logger with templated sink type -// Example: spdlog::create("mylog", "dailylog_filename", "txt"); -template -std::shared_ptr create(const std::string& logger_name, Args...); - -// Register the given logger with the given name -void register_logger(std::shared_ptr logger); - -// Drop the reference to the given logger -void drop(const std::string& name); - -// Drop all references -void drop_all(); - -/////////////////////////////////////////////////////////////////////////////// -// -// Macros to be display source file & line -// Trace & Debug can be switched on/off at compile time for zero cost debug statements. -// Uncomment SPDLOG_DEBUG_ON/SPDLOG_TRACE_ON in teakme.h to enable. -// -// Example: -// spdlog::set_level(spdlog::level::debug); -// SPDLOG_DEBUG(my_logger, "Some debug message {} {}", 1, 3.2); -/////////////////////////////////////////////////////////////////////////////// - -#ifdef SPDLOG_TRACE_ON -#define SPDLOG_TRACE(logger, ...) \ - logger->trace(__VA_ARGS__) << " (" << __FILE__ << " #" << __LINE__ << ")"; -#else -#define SPDLOG_TRACE(logger, ...) -#endif - -#ifdef SPDLOG_DEBUG_ON -#define SPDLOG_DEBUG(logger, ...) \ - logger->debug(__VA_ARGS__) << " (" << __FILE__ << " #" << __LINE__ << ")"; -#else -#define SPDLOG_DEBUG(logger, ...) -#endif -} - -#include "details/spdlog_impl.h" diff --git a/cameradar_standalone/include/stream_model.h b/cameradar_standalone/include/stream_model.h deleted file mode 100644 index 3add6b0..0000000 --- a/cameradar_standalone/include/stream_model.h +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2016 Etix Labs -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -#include -#include - -namespace etix { -namespace cameradar { - -struct stream_model { - // Ex : "172.16.100.113" - std::string address; - // Ex : 8554 - unsigned int port; - // Ex : "admin" - std::string username = ""; - // Ex : "123456" - std::string password = ""; - // Ex : "live.sdp" - std::string route = ""; - - // Ex : "rtsp" - std::string service_name; - // Ex : "Vivotek HDCam" - std::string product; - // Ex : "RTSP" - std::string protocol; - // Ex : "Open" - std::string state; - - // Ex : "true" - bool path_found = false; - // Ex : "true" - bool ids_found = false; - - // Ex : "/thumbnails/cameradar" - std::string thumbnail_path = ""; -}; -Json::Value deserialize(const stream_model& model); -} -} diff --git a/cameradar_standalone/include/tasks/creds_attack.h b/cameradar_standalone/include/tasks/creds_attack.h deleted file mode 100644 index f9247c0..0000000 --- a/cameradar_standalone/include/tasks/creds_attack.h +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2016 Etix Labs -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -#include // cacheManager -#include // task interface -#include // send DESCRIBE through cURL -#include // std::async & std::future -#include // signals -#include // data model - -namespace etix { -namespace cameradar { - -class creds_attack : public etix::cameradar::cameradar_task { - const configuration& conf; - std::shared_ptr cache; - std::string nmap_output; - -public: - creds_attack() = delete; - creds_attack(std::shared_ptr cache, - const configuration& conf, - std::string nmap_output) - : conf(conf), cache(cache), nmap_output(nmap_output) {} - creds_attack(const creds_attack& ref) = delete; - - virtual bool run() const; - - bool test_ids(const etix::cameradar::stream_model& cit, - const std::string& pit, - const std::string& uit) const; - bool attack_camera_creds(const stream_model& stream) const; -}; -} -} diff --git a/cameradar_standalone/include/tasks/mapping.h b/cameradar_standalone/include/tasks/mapping.h deleted file mode 100644 index 5b9a5f2..0000000 --- a/cameradar_standalone/include/tasks/mapping.h +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2016 Etix Labs -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -#include // task interface -#include // launch_command -#include // launch_command -#include // fmt -#include // data model -#include // cacheManager - -namespace etix { -namespace cameradar { - -class mapping : public etix::cameradar::cameradar_task { - const configuration& conf; - std::shared_ptr cache; - std::string nmap_output; - -public: - mapping() = delete; - mapping(std::shared_ptr cache, - const configuration& conf, - std::string nmap_output) - : conf(conf), cache(cache), nmap_output(nmap_output) {} - mapping(const mapping& ref) = delete; - - virtual bool run() const; -}; -} -} diff --git a/cameradar_standalone/include/tasks/parsing.h b/cameradar_standalone/include/tasks/parsing.h deleted file mode 100644 index 374e441..0000000 --- a/cameradar_standalone/include/tasks/parsing.h +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2016 Etix Labs -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -#include // task interface -#include // parsing -#include // data model -#include // cacheManager - -namespace etix { -namespace cameradar { - -class parsing : public etix::cameradar::cameradar_task { - const configuration& conf; - std::shared_ptr cache; - std::string nmap_output; - -public: - parsing() = delete; - parsing(std::shared_ptr cache, - const configuration& conf, - std::string nmap_output) - : conf(conf), cache(cache), nmap_output(nmap_output) {} - parsing(const parsing& ref) = delete; - - virtual bool run() const; - - void parse_camera(TiXmlElement*, std::vector& data) const; - - bool print_detected_cameras(const std::vector& data) const; -}; -} -} diff --git a/cameradar_standalone/include/tasks/path_attack.h b/cameradar_standalone/include/tasks/path_attack.h deleted file mode 100644 index 9961737..0000000 --- a/cameradar_standalone/include/tasks/path_attack.h +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2016 Etix Labs -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -#include // cacheManager -#include // task interface -#include // cURL client for discovery -#include // send DESCRIBE through cURL -#include // std::async & std::future -#include // LOG -#include // std::shared_ptr -#include // signals -#include // data model - -namespace etix { -namespace cameradar { - -class path_attack : public etix::cameradar::cameradar_task { - const configuration& conf; - std::shared_ptr cache; - std::string nmap_output; - -public: - path_attack() = delete; - path_attack(std::shared_ptr cache, - const configuration& conf, - std::string nmap_output) - : conf(conf), cache(cache), nmap_output(nmap_output) {} - path_attack(const path_attack& ref) = delete; - - virtual bool run() const; - - bool test_path(const etix::cameradar::stream_model& cit, const std::string& it) const; - bool attack_camera_path(const stream_model& stream) const; -}; -} -} diff --git a/cameradar_standalone/include/tasks/print.h b/cameradar_standalone/include/tasks/print.h deleted file mode 100644 index 8b78322..0000000 --- a/cameradar_standalone/include/tasks/print.h +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2016 Etix Labs -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -#include // cacheManager -#include // task interface -#include // std::ofstream -#include // std::ofstream -#include // data model - -namespace etix { -namespace cameradar { - -static const std::string default_result_file_path = "/tmp/shared/result.json"; - -class print : public etix::cameradar::cameradar_task { - const configuration& conf; - std::shared_ptr cache; - std::string nmap_output; - -public: - print() = delete; - print(std::shared_ptr cache, const configuration& conf, std::string nmap_output) - : conf(conf), cache(cache), nmap_output(nmap_output) {} - print(const print& ref) = delete; - - virtual bool run() const; -}; -} -} diff --git a/cameradar_standalone/include/tasks/stream_check.h b/cameradar_standalone/include/tasks/stream_check.h deleted file mode 100644 index df89e7c..0000000 --- a/cameradar_standalone/include/tasks/stream_check.h +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2016 Etix Labs -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -#include // task interface -#include // signals -#include // data model -#include // cacheManager - -#include -#include -#include - -namespace etix { -namespace cameradar { - -class stream_check : public etix::cameradar::cameradar_task { - const configuration& conf; - std::shared_ptr cache; - std::string nmap_output; - -public: - stream_check() = delete; - stream_check(std::shared_ptr cache, - const configuration& conf, - std::string nmap_output) - : conf(conf), cache(cache), nmap_output(nmap_output) {} - stream_check(const stream_check& ref) = delete; - - virtual bool run() const; -}; -} -} diff --git a/cameradar_standalone/include/tasks/thumbnail.h b/cameradar_standalone/include/tasks/thumbnail.h deleted file mode 100644 index bfd94ea..0000000 --- a/cameradar_standalone/include/tasks/thumbnail.h +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2016 Etix Labs -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -#include // cacheManager -#include // task interface -#include // fmt -#include // std::async & std::future -#include // launch_command -#include // make_path -#include // signals -#include // data model - -namespace etix { -namespace cameradar { - -class thumbnail : public etix::cameradar::cameradar_task { - const configuration& conf; - std::shared_ptr cache; - std::string nmap_output; - -public: - thumbnail() = delete; - thumbnail(std::shared_ptr cache, - const configuration& conf, - std::string nmap_output) - : conf(conf), cache(cache), nmap_output(nmap_output) {} - thumbnail(const thumbnail& ref) = delete; - - virtual bool run() const; - - std::string build_output_file_path(const std::string& path) const; - bool generate_thumbnail(const stream_model& stream) const; -}; -} -} diff --git a/cameradar_standalone/include/tinystr.h b/cameradar_standalone/include/tinystr.h deleted file mode 100644 index ac83223..0000000 --- a/cameradar_standalone/include/tinystr.h +++ /dev/null @@ -1,303 +0,0 @@ -/* -www.sourceforge.net/projects/tinyxml - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any -damages arising from the use of this software. - -Permission is granted to anyone to use this software for any -purpose, including commercial applications, and to alter it and -redistribute it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must -not claim that you wrote the original software. If you use this -software in a product, an acknowledgment in the product documentation -would be appreciated but is not required. - -2. Altered source versions must be plainly marked as such, and -must not be misrepresented as being the original software. - -3. This notice may not be removed or altered from any source -distribution. -*/ - -#ifndef TIXML_USE_STL - -#ifndef TIXML_STRING_INCLUDED -#define TIXML_STRING_INCLUDED - -#include -#include - -/* The support for explicit isn't that universal, and it isn't really - required - it is used to check that the TiXmlString class isn't - incorrectly - used. Be nice to old compilers and macro it here: -*/ -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -// Microsoft visual studio, version 6 and higher. -#define TIXML_EXPLICIT explicit -#elif defined(__GNUC__) && (__GNUC__ >= 3) -// GCC version 3 and higher.s -#define TIXML_EXPLICIT explicit -#else -#define TIXML_EXPLICIT -#endif - -/* - TiXmlString is an emulation of a subset of the std::string template. - Its purpose is to allow compiling TinyXML on compilers with no or poor STL - support. - Only the member functions relevant to the TinyXML project have been - implemented. - The buffer allocation is made by a simplistic power of 2 like mechanism : if - we increase - a string and there's no more room, we allocate a buffer twice as big as we - need. -*/ -class TiXmlString { -public: - // The size type used - typedef size_t size_type; - - // Error value for find primitive - static const size_type npos; // = -1; - - // TiXmlString empty constructor - TiXmlString() : rep_(&nullrep_) {} - - // TiXmlString copy constructor - TiXmlString(const TiXmlString& copy) : rep_(0) { - init(copy.length()); - memcpy(start(), copy.data(), length()); - } - - // TiXmlString constructor, based on a string - TIXML_EXPLICIT - TiXmlString(const char* copy) - : rep_(0) { - init(static_cast(strlen(copy))); - memcpy(start(), copy, length()); - } - - // TiXmlString constructor, based on a string - TIXML_EXPLICIT - TiXmlString(const char* str, size_type len) - : rep_(0) { - init(len); - memcpy(start(), str, len); - } - - // TiXmlString destructor - ~TiXmlString() { quit(); } - - TiXmlString& operator=(const char* copy) { return assign(copy, (size_type)strlen(copy)); } - - TiXmlString& operator=(const TiXmlString& copy) { return assign(copy.start(), copy.length()); } - - // += operator. Maps to append - TiXmlString& operator+=(const char* suffix) { - return append(suffix, static_cast(strlen(suffix))); - } - - // += operator. Maps to append - TiXmlString& operator+=(char single) { return append(&single, 1); } - - // += operator. Maps to append - TiXmlString& operator+=(const TiXmlString& suffix) { - return append(suffix.data(), suffix.length()); - } - - // Convert a TiXmlString into a null-terminated char * - const char* - c_str() const { - return rep_->str; - } - - // Convert a TiXmlString into a char * (need not be null terminated). - const char* - data() const { - return rep_->str; - } - - // Return the length of a TiXmlString - size_type - length() const { - return rep_->size; - } - - // Alias for length() - size_type - size() const { - return rep_->size; - } - - // Checks if a TiXmlString is empty - bool - empty() const { - return rep_->size == 0; - } - - // Return capacity of string - size_type - capacity() const { - return rep_->capacity; - } - - // single char extraction - const char& - at(size_type index) const { - assert(index < length()); - return rep_->str[index]; - } - - // [] operator - char& operator[](size_type index) const { - assert(index < length()); - return rep_->str[index]; - } - - // find a char in a string. Return TiXmlString::npos if not found - size_type - find(char lookup) const { - return find(lookup, 0); - } - - // find a char in a string from an offset. Return TiXmlString::npos if not - // found - size_type - find(char tofind, size_type offset) const { - if (offset >= length()) return npos; - - for (const char* p = c_str() + offset; *p != '\0'; ++p) { - if (*p == tofind) return static_cast(p - c_str()); - } - return npos; - } - - void - clear() { - // Lee: - // The original was just too strange, though correct: - // TiXmlString().swap(*this); - // Instead use the quit & re-init: - quit(); - init(0, 0); - } - - /* Function to reserve a big amount of data when we know we'll need it. Be - aware that this - function DOES NOT clear the content of the TiXmlString if any exists. - */ - void reserve(size_type cap); - - TiXmlString& assign(const char* str, size_type len); - - TiXmlString& append(const char* str, size_type len); - - void - swap(TiXmlString& other) { - Rep* r = rep_; - rep_ = other.rep_; - other.rep_ = r; - } - -private: - void - init(size_type sz) { - init(sz, sz); - } - void - set_size(size_type sz) { - rep_->str[rep_->size = sz] = '\0'; - } - char* - start() const { - return rep_->str; - } - char* - finish() const { - return rep_->str + rep_->size; - } - - struct Rep { - size_type size, capacity; - char str[1]; - }; - - void - init(size_type sz, size_type cap) { - if (cap) { - // Lee: the original form: - // rep_ = static_cast(operator new(sizeof(Rep) + cap)); - // doesn't work in some cases of new being overloaded. Switching - // to the normal allocation, although use an 'int' for systems - // that are overly picky about structure alignment. - const size_type bytesNeeded = sizeof(Rep) + cap; - const size_type intsNeeded = (bytesNeeded + sizeof(int) - 1) / sizeof(int); - rep_ = reinterpret_cast(new int[intsNeeded]); - - rep_->str[rep_->size = sz] = '\0'; - rep_->capacity = cap; - } else { - rep_ = &nullrep_; - } - } - - void - quit() { - if (rep_ != &nullrep_) { - // The rep_ is really an array of ints. (see the allocator, above). - // Cast it back before delete, so the compiler won't incorrectly call - // destructors. - delete[](reinterpret_cast(rep_)); - } - } - - Rep* rep_; - static Rep nullrep_; -}; - -inline bool operator==(const TiXmlString& a, const TiXmlString& b) { - return (a.length() == b.length()) // optimization on some platforms - && (strcmp(a.c_str(), b.c_str()) == 0); // actual compare -} -inline bool operator<(const TiXmlString& a, const TiXmlString& b) { - return strcmp(a.c_str(), b.c_str()) < 0; -} - -inline bool operator!=(const TiXmlString& a, const TiXmlString& b) { return !(a == b); } -inline bool operator>(const TiXmlString& a, const TiXmlString& b) { return b < a; } -inline bool operator<=(const TiXmlString& a, const TiXmlString& b) { return !(b < a); } -inline bool operator>=(const TiXmlString& a, const TiXmlString& b) { return !(a < b); } - -inline bool operator==(const TiXmlString& a, const char* b) { return strcmp(a.c_str(), b) == 0; } -inline bool operator==(const char* a, const TiXmlString& b) { return b == a; } -inline bool operator!=(const TiXmlString& a, const char* b) { return !(a == b); } -inline bool operator!=(const char* a, const TiXmlString& b) { return !(b == a); } - -TiXmlString operator+(const TiXmlString& a, const TiXmlString& b); -TiXmlString operator+(const TiXmlString& a, const char* b); -TiXmlString operator+(const char* a, const TiXmlString& b); - -/* - TiXmlOutStream is an emulation of std::ostream. It is based on TiXmlString. - Only the operators that we need for TinyXML have been developped. -*/ -class TiXmlOutStream : public TiXmlString { -public: - // TiXmlOutStream << operator. - TiXmlOutStream& operator<<(const TiXmlString& in) { - *this += in; - return *this; - } - - // TiXmlOutStream << operator. - TiXmlOutStream& operator<<(const char* in) { - *this += in; - return *this; - } -}; - -#endif // TIXML_STRING_INCLUDED -#endif // TIXML_USE_STL diff --git a/cameradar_standalone/include/tinyxml.h b/cameradar_standalone/include/tinyxml.h deleted file mode 100644 index 1770a2b..0000000 --- a/cameradar_standalone/include/tinyxml.h +++ /dev/null @@ -1,2277 +0,0 @@ -/* -www.sourceforge.net/projects/tinyxml -Original code by Lee Thomason (www.grinninglizard.com) - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any -damages arising from the use of this software. - -Permission is granted to anyone to use this software for any -purpose, including commercial applications, and to alter it and -redistribute it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must -not claim that you wrote the original software. If you use this -software in a product, an acknowledgment in the product documentation -would be appreciated but is not required. - -2. Altered source versions must be plainly marked as such, and -must not be misrepresented as being the original software. - -3. This notice may not be removed or altered from any source -distribution. -*/ - -#ifndef TINYXML_INCLUDED -#define TINYXML_INCLUDED - -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable : 4530) -#pragma warning(disable : 4786) -#endif - -#include -#include -#include -#include -#include - -// Help out windows: -#if defined(_DEBUG) && !defined(DEBUG) -#define DEBUG -#endif - -#ifdef TIXML_USE_STL -#include -#include -#include -#define TIXML_STRING std::string -#else -#include "tinystr.h" -#define TIXML_STRING TiXmlString -#endif - -// Deprecated library function hell. Compilers want to use the -// new safe versions. This probably doesn't fully address the problem, -// but it gets closer. There are too many compilers for me to fully -// test. If you get compilation troubles, undefine TIXML_SAFE -#define TIXML_SAFE - -#ifdef TIXML_SAFE -#if defined(_MSC_VER) && (_MSC_VER >= 1400) -// Microsoft visual studio, version 2005 and higher. -#define TIXML_SNPRINTF _snprintf_s -#define TIXML_SSCANF sscanf_s -#elif defined(_MSC_VER) && (_MSC_VER >= 1200) -// Microsoft visual studio, version 6 and higher. -//#pragma message( "Using _sn* functions." ) -#define TIXML_SNPRINTF _snprintf -#define TIXML_SSCANF sscanf -#elif defined(__GNUC__) && (__GNUC__ >= 3) -// GCC version 3 and higher.s -//#warning( "Using sn* functions." ) -#define TIXML_SNPRINTF snprintf -#define TIXML_SSCANF sscanf -#else -#define TIXML_SNPRINTF snprintf -#define TIXML_SSCANF sscanf -#endif -#endif - -class TiXmlDocument; -class TiXmlElement; -class TiXmlComment; -class TiXmlUnknown; -class TiXmlAttribute; -class TiXmlText; -class TiXmlDeclaration; -class TiXmlParsingData; - -const int TIXML_MAJOR_VERSION = 2; -const int TIXML_MINOR_VERSION = 6; -const int TIXML_PATCH_VERSION = 2; - -/* Internal structure for tracking location of items - in the XML file. -*/ -struct TiXmlCursor { - TiXmlCursor() { Clear(); } - void - Clear() { - row = col = -1; - } - - int row; // 0 based. - int col; // 0 based. -}; - -/** - Implements the interface to the "Visitor pattern" (see the Accept() - method.) - If you call the Accept() method, it requires being passed a TiXmlVisitor - class to handle callbacks. For nodes that contain other nodes (Document, - Element) - you will get called with a VisitEnter/VisitExit pair. Nodes that are - always leaves - are simply called with Visit(). - - If you return 'true' from a Visit method, recursive parsing will - continue. If you return - false, no children of this node or its sibilings will be Visited. - - All flavors of Visit methods have a default implementation that returns - 'true' (continue - visiting). You need to only override methods that are interesting to - you. - - Generally Accept() is called on the TiXmlDocument, although all nodes - suppert Visiting. - - You should never change the document from a callback. - - @sa TiXmlNode::Accept() -*/ -class TiXmlVisitor { -public: - virtual ~TiXmlVisitor() {} - - /// Visit a document. - virtual bool - VisitEnter(const TiXmlDocument& /*doc*/) { - return true; - } - /// Visit a document. - virtual bool - VisitExit(const TiXmlDocument& /*doc*/) { - return true; - } - - /// Visit an element. - virtual bool - VisitEnter(const TiXmlElement& /*element*/, const TiXmlAttribute* /*firstAttribute*/) { - return true; - } - /// Visit an element. - virtual bool - VisitExit(const TiXmlElement& /*element*/) { - return true; - } - - /// Visit a declaration - virtual bool - Visit(const TiXmlDeclaration& /*declaration*/) { - return true; - } - /// Visit a text node - virtual bool - Visit(const TiXmlText& /*text*/) { - return true; - } - /// Visit a comment node - virtual bool - Visit(const TiXmlComment& /*comment*/) { - return true; - } - /// Visit an unknown node - virtual bool - Visit(const TiXmlUnknown& /*unknown*/) { - return true; - } -}; - -// Only used by Attribute::Query functions -enum { TIXML_SUCCESS, TIXML_NO_ATTRIBUTE, TIXML_WRONG_TYPE }; - -// Used by the parsing routines. -enum TiXmlEncoding { TIXML_ENCODING_UNKNOWN, TIXML_ENCODING_UTF8, TIXML_ENCODING_LEGACY }; - -const TiXmlEncoding TIXML_DEFAULT_ENCODING = TIXML_ENCODING_UNKNOWN; - -/** TiXmlBase is a base class for every class in TinyXml. - It does little except to establish that TinyXml classes - can be printed and provide some utility functions. - - In XML, the document and elements can contain - other elements and other types of nodes. - - @verbatim - A Document can contain: Element (container or leaf) - Comment (leaf) - Unknown (leaf) - Declaration( leaf ) - - An Element can contain: Element (container or leaf) - Text (leaf) - Attributes (not on tree) - Comment (leaf) - Unknown (leaf) - - A Decleration contains: Attributes (not on tree) - @endverbatim -*/ -class TiXmlBase { - friend class TiXmlNode; - friend class TiXmlElement; - friend class TiXmlDocument; - -public: - TiXmlBase() : userData(0) {} - virtual ~TiXmlBase() {} - - /** All TinyXml classes can print themselves to a filestream - or the string class (TiXmlString in non-STL mode, std::string - in STL mode.) Either or both cfile and str can be null. - - This is a formatted print, and will insert - tabs and newlines. - - (For an unformatted stream, use the << operator.) - */ - virtual void Print(FILE* cfile, int depth) const = 0; - - /** The world does not agree on whether white space should be kept or - not. In order to make everyone happy, these global, static functions - are provided to set whether or not TinyXml will condense all white - space - into a single space or not. The default is to condense. Note changing - this - value is not thread safe. - */ - static void - SetCondenseWhiteSpace(bool condense) { - condenseWhiteSpace = condense; - } - - /// Return the current white space setting. - static bool - IsWhiteSpaceCondensed() { - return condenseWhiteSpace; - } - - /** Return the position, in the original source file, of this node or - attribute. - The row and column are 1-based. (That is the first row and first - column is - 1,1). If the returns values are 0 or less, then the parser does not - have - a row and column value. - - Generally, the row and column value will be set when the - TiXmlDocument::Load(), - TiXmlDocument::LoadFile(), or any TiXmlNode::Parse() is called. It - will NOT be set - when the DOM was created from operator>>. - - The values reflect the initial load. Once the DOM is modified - programmatically - (by adding or changing nodes and attributes) the new values will NOT - update to - reflect changes in the document. - - There is a minor performance cost to computing the row and column. - Computation - can be disabled if TiXmlDocument::SetTabSize() is called with 0 as the - value. - - @sa TiXmlDocument::SetTabSize() - */ - int - Row() const { - return location.row + 1; - } - int - Column() const { - return location.col + 1; - } ///< See Row() - - void - SetUserData(void* user) { - userData = user; - } ///< Set a pointer to arbitrary user data. - void* - GetUserData() { - return userData; - } ///< Get a pointer to arbitrary user data. - const void* - GetUserData() const { - return userData; - } ///< Get a pointer to arbitrary user data. - - // Table that returs, for a given lead byte, the total number of bytes - // in the UTF-8 sequence. - static const int utf8ByteTable[256]; - - virtual const char* Parse(const char* p, - TiXmlParsingData* data, - TiXmlEncoding encoding /*= TIXML_ENCODING_UNKNOWN */) = 0; - - /** Expands entities in a string. Note this should not contian the tag's '<', - '>', etc, - or they will be transformed into entities! - */ - static void EncodeString(const TIXML_STRING& str, TIXML_STRING* out); - - enum { - TIXML_NO_ERROR = 0, - TIXML_ERROR, - TIXML_ERROR_OPENING_FILE, - TIXML_ERROR_PARSING_ELEMENT, - TIXML_ERROR_FAILED_TO_READ_ELEMENT_NAME, - TIXML_ERROR_READING_ELEMENT_VALUE, - TIXML_ERROR_READING_ATTRIBUTES, - TIXML_ERROR_PARSING_EMPTY, - TIXML_ERROR_READING_END_TAG, - TIXML_ERROR_PARSING_UNKNOWN, - TIXML_ERROR_PARSING_COMMENT, - TIXML_ERROR_PARSING_DECLARATION, - TIXML_ERROR_DOCUMENT_EMPTY, - TIXML_ERROR_EMBEDDED_NULL, - TIXML_ERROR_PARSING_CDATA, - TIXML_ERROR_DOCUMENT_TOP_ONLY, - - TIXML_ERROR_STRING_COUNT - }; - -protected: - static const char* SkipWhiteSpace(const char*, TiXmlEncoding encoding); - - inline static bool - IsWhiteSpace(char c) { - return (isspace((unsigned char)c) || c == '\n' || c == '\r'); - } - inline static bool - IsWhiteSpace(int c) { - if (c < 256) return IsWhiteSpace((char)c); - return false; // Again, only truly correct for English/Latin...but usually - // works. - } - -#ifdef TIXML_USE_STL - static bool StreamWhiteSpace(std::istream* in, TIXML_STRING* tag); - static bool StreamTo(std::istream* in, int character, TIXML_STRING* tag); -#endif - - /* Reads an XML name into the string provided. Returns - a pointer just past the last character of the name, - or 0 if the function has an error. - */ - static const char* ReadName(const char* p, TIXML_STRING* name, TiXmlEncoding encoding); - - /* Reads text. Returns a pointer past the given end tag. - Wickedly complex options, but it keeps the (sensitive) code in one - place. - */ - static const char* ReadText(const char* in, // where to start - TIXML_STRING* text, // the string read - bool ignoreWhiteSpace, // whether to keep the white space - const char* endTag, // what ends this text - bool ignoreCase, // whether to ignore case in the end tag - TiXmlEncoding encoding); // the current encoding - - // If an entity has been found, transform it into a character. - static const char* GetEntity(const char* in, char* value, int* length, TiXmlEncoding encoding); - - // Get a character, while interpreting entities. - // The length can be from 0 to 4 bytes. - inline static const char* - GetChar(const char* p, char* _value, int* length, TiXmlEncoding encoding) { - assert(p); - if (encoding == TIXML_ENCODING_UTF8) { - *length = utf8ByteTable[*((const unsigned char*)p)]; - assert(*length >= 0 && *length < 5); - } else { - *length = 1; - } - - if (*length == 1) { - if (*p == '&') return GetEntity(p, _value, length, encoding); - *_value = *p; - return p + 1; - } else if (*length) { - // strncpy( _value, p, *length ); // lots of compilers don't like - // this function (unsafe), - // and the null terminator isn't needed - for (int i = 0; p[i] && i < *length; ++i) { _value[i] = p[i]; } - return p + (*length); - } else { - // Not valid text. - return 0; - } - } - - // Return true if the next characters in the stream are any of the endTag - // sequences. - // Ignore case only works for english, and should only be relied on when - // comparing - // to English words: StringEqual( p, "version", true ) is fine. - static bool - StringEqual(const char* p, const char* endTag, bool ignoreCase, TiXmlEncoding encoding); - - static const char* errorString[TIXML_ERROR_STRING_COUNT]; - - TiXmlCursor location; - - /// Field containing a generic user pointer - void* userData; - - // None of these methods are reliable for any language except English. - // Good for approximation, not great for accuracy. - static int IsAlpha(unsigned char anyByte, TiXmlEncoding encoding); - static int IsAlphaNum(unsigned char anyByte, TiXmlEncoding encoding); - inline static int - ToLower(int v, TiXmlEncoding encoding) { - if (encoding == TIXML_ENCODING_UTF8) { - if (v < 128) return tolower(v); - return v; - } else { - return tolower(v); - } - } - static void ConvertUTF32ToUTF8(unsigned long input, char* output, int* length); - -private: - TiXmlBase(const TiXmlBase&); // not implemented. - void operator=(const TiXmlBase& base); // not allowed. - - struct Entity { - const char* str; - unsigned int strLength; - char chr; - }; - enum { - NUM_ENTITY = 5, - MAX_ENTITY_LENGTH = 6 - - }; - static Entity entity[NUM_ENTITY]; - static bool condenseWhiteSpace; -}; - -/** The parent class for everything in the Document Object Model. - (Except for attributes). - Nodes have siblings, a parent, and children. A node can be - in a document, or stand on its own. The type of a TiXmlNode - can be queried, and it can be cast to its more defined type. -*/ -class TiXmlNode : public TiXmlBase { - friend class TiXmlDocument; - friend class TiXmlElement; - -public: -#ifdef TIXML_USE_STL - - /** An input stream operator, for every class. Tolerant of newlines and - formatting, but doesn't expect them. - */ - friend std::istream& operator>>(std::istream& in, TiXmlNode& base); - - /** An output stream operator, for every class. Note that this outputs - without any newlines or formatting, as opposed to Print(), which - includes tabs and new lines. - - The operator<< and operator>> are not completely symmetric. Writing - a node to a stream is very well defined. You'll get a nice stream - of output, without any extra whitespace or newlines. - - But reading is not as well defined. (As it always is.) If you create - a TiXmlElement (for example) and read that from an input stream, - the text needs to define an element or junk will result. This is - true of all input streams, but it's worth keeping in mind. - - A TiXmlDocument will read nodes until it reads a root element, and - all the children of that root element. - */ - friend std::ostream& operator<<(std::ostream& out, const TiXmlNode& base); - - /// Appends the XML node or attribute to a std::string. - friend std::string& operator<<(std::string& out, const TiXmlNode& base); - -#endif - - /** The types of XML nodes supported by TinyXml. (All the - unsupported types are picked up by UNKNOWN.) - */ - enum NodeType { - TINYXML_DOCUMENT, - TINYXML_ELEMENT, - TINYXML_COMMENT, - TINYXML_UNKNOWN, - TINYXML_TEXT, - TINYXML_DECLARATION, - TINYXML_TYPECOUNT - }; - - virtual ~TiXmlNode(); - - /** The meaning of 'value' changes for the specific type of - TiXmlNode. - @verbatim - Document: filename of the xml file - Element: name of the element - Comment: the comment text - Unknown: the tag contents - Text: the text string - @endverbatim - - The subclasses will wrap this function. - */ - const char* - Value() const { - return value.c_str(); - } - -#ifdef TIXML_USE_STL - /** Return Value() as a std::string. If you only use STL, - this is more efficient than calling Value(). - Only available in STL mode. - */ - const std::string& - ValueStr() const { - return value; - } -#endif - - const TIXML_STRING& - ValueTStr() const { - return value; - } - - /** Changes the value of the node. Defined as: - @verbatim - Document: filename of the xml file - Element: name of the element - Comment: the comment text - Unknown: the tag contents - Text: the text string - @endverbatim - */ - void - SetValue(const char* _value) { - value = _value; - } - -#ifdef TIXML_USE_STL - /// STL std::string form. - void - SetValue(const std::string& _value) { - value = _value; - } -#endif - - /// Delete all the children of this node. Does not affect 'this'. - void Clear(); - - /// One step up the DOM. - TiXmlNode* - Parent() { - return parent; - } - const TiXmlNode* - Parent() const { - return parent; - } - - const TiXmlNode* - FirstChild() const { - return firstChild; - } ///< The first child of this node. Will be null if there are no children. - TiXmlNode* - FirstChild() { - return firstChild; - } - const TiXmlNode* FirstChild(const char* value) const; ///< The first child of - /// this node with the - /// matching 'value'. - /// Will be null if none - /// found. - /// The first child of this node with the matching 'value'. Will be null if - /// none found. - TiXmlNode* - FirstChild(const char* _value) { - // Call through to the const version - safe since nothing is changed. - // Exiting syntax: cast this to a const (always safe) - // call the method, cast the return back to non-const. - return const_cast((const_cast(this))->FirstChild(_value)); - } - const TiXmlNode* - LastChild() const { - return lastChild; - } /// The last child of this node. Will be null if there are no children. - TiXmlNode* - LastChild() { - return lastChild; - } - - const TiXmlNode* LastChild(const char* value) const; /// The last child of - /// this node matching - /// 'value'. Will be null - /// if there are no - /// children. - TiXmlNode* - LastChild(const char* _value) { - return const_cast((const_cast(this))->LastChild(_value)); - } - -#ifdef TIXML_USE_STL - const TiXmlNode* - FirstChild(const std::string& _value) const { - return FirstChild(_value.c_str()); - } ///< STL std::string form. - TiXmlNode* - FirstChild(const std::string& _value) { - return FirstChild(_value.c_str()); - } ///< STL std::string form. - const TiXmlNode* - LastChild(const std::string& _value) const { - return LastChild(_value.c_str()); - } ///< STL std::string form. - TiXmlNode* - LastChild(const std::string& _value) { - return LastChild(_value.c_str()); - } ///< STL std::string form. -#endif - - /** An alternate way to walk the children of a node. - One way to iterate over nodes is: - @verbatim - for( child = parent->FirstChild(); child; child = - child->NextSibling() ) - @endverbatim - - IterateChildren does the same thing with the syntax: - @verbatim - child = 0; - while( child = parent->IterateChildren( child ) ) - @endverbatim - - IterateChildren takes the previous child as input and finds - the next one. If the previous child is null, it returns the - first. IterateChildren will return null when done. - */ - const TiXmlNode* IterateChildren(const TiXmlNode* previous) const; - TiXmlNode* - IterateChildren(const TiXmlNode* previous) { - return const_cast( - (const_cast(this))->IterateChildren(previous)); - } - - /// This flavor of IterateChildren searches for children with a particular - /// 'value' - const TiXmlNode* IterateChildren(const char* value, const TiXmlNode* previous) const; - TiXmlNode* - IterateChildren(const char* _value, const TiXmlNode* previous) { - return const_cast( - (const_cast(this))->IterateChildren(_value, previous)); - } - -#ifdef TIXML_USE_STL - const TiXmlNode* - IterateChildren(const std::string& _value, const TiXmlNode* previous) const { - return IterateChildren(_value.c_str(), previous); - } ///< STL std::string form. - TiXmlNode* - IterateChildren(const std::string& _value, const TiXmlNode* previous) { - return IterateChildren(_value.c_str(), previous); - } ///< STL std::string form. -#endif - - /** Add a new node related to this. Adds a child past the LastChild. - Returns a pointer to the new object or NULL if an error occured. - */ - TiXmlNode* InsertEndChild(const TiXmlNode& addThis); - - /** Add a new node related to this. Adds a child past the LastChild. - - NOTE: the node to be added is passed by pointer, and will be - henceforth owned (and deleted) by tinyXml. This method is efficient - and avoids an extra copy, but should be used with care as it - uses a different memory model than the other insert functions. - - @sa InsertEndChild - */ - TiXmlNode* LinkEndChild(TiXmlNode* addThis); - - /** Add a new node related to this. Adds a child before the specified child. - Returns a pointer to the new object or NULL if an error occured. - */ - TiXmlNode* InsertBeforeChild(TiXmlNode* beforeThis, const TiXmlNode& addThis); - - /** Add a new node related to this. Adds a child after the specified child. - Returns a pointer to the new object or NULL if an error occured. - */ - TiXmlNode* InsertAfterChild(TiXmlNode* afterThis, const TiXmlNode& addThis); - - /** Replace a child of this node. - Returns a pointer to the new object or NULL if an error occured. - */ - TiXmlNode* ReplaceChild(TiXmlNode* replaceThis, const TiXmlNode& withThis); - - /// Delete a child of this node. - bool RemoveChild(TiXmlNode* removeThis); - - /// Navigate to a sibling node. - const TiXmlNode* - PreviousSibling() const { - return prev; - } - TiXmlNode* - PreviousSibling() { - return prev; - } - - /// Navigate to a sibling node. - const TiXmlNode* PreviousSibling(const char*) const; - TiXmlNode* - PreviousSibling(const char* _prev) { - return const_cast((const_cast(this))->PreviousSibling(_prev)); - } - -#ifdef TIXML_USE_STL - const TiXmlNode* - PreviousSibling(const std::string& _value) const { - return PreviousSibling(_value.c_str()); - } ///< STL std::string form. - TiXmlNode* - PreviousSibling(const std::string& _value) { - return PreviousSibling(_value.c_str()); - } ///< STL std::string form. - const TiXmlNode* - NextSibling(const std::string& _value) const { - return NextSibling(_value.c_str()); - } ///< STL std::string form. - TiXmlNode* - NextSibling(const std::string& _value) { - return NextSibling(_value.c_str()); - } ///< STL std::string form. -#endif - - /// Navigate to a sibling node. - const TiXmlNode* - NextSibling() const { - return next; - } - TiXmlNode* - NextSibling() { - return next; - } - - /// Navigate to a sibling node with the given 'value'. - const TiXmlNode* NextSibling(const char*) const; - TiXmlNode* - NextSibling(const char* _next) { - return const_cast((const_cast(this))->NextSibling(_next)); - } - - /** Convenience function to get through elements. - Calls NextSibling and ToElement. Will skip all non-Element - nodes. Returns 0 if there is not another element. - */ - const TiXmlElement* NextSiblingElement() const; - TiXmlElement* - NextSiblingElement() { - return const_cast( - (const_cast(this))->NextSiblingElement()); - } - - /** Convenience function to get through elements. - Calls NextSibling and ToElement. Will skip all non-Element - nodes. Returns 0 if there is not another element. - */ - const TiXmlElement* NextSiblingElement(const char*) const; - TiXmlElement* - NextSiblingElement(const char* _next) { - return const_cast( - (const_cast(this))->NextSiblingElement(_next)); - } - -#ifdef TIXML_USE_STL - const TiXmlElement* - NextSiblingElement(const std::string& _value) const { - return NextSiblingElement(_value.c_str()); - } ///< STL std::string form. - TiXmlElement* - NextSiblingElement(const std::string& _value) { - return NextSiblingElement(_value.c_str()); - } ///< STL std::string form. -#endif - - /// Convenience function to get through elements. - const TiXmlElement* FirstChildElement() const; - TiXmlElement* - FirstChildElement() { - return const_cast((const_cast(this))->FirstChildElement()); - } - - /// Convenience function to get through elements. - const TiXmlElement* FirstChildElement(const char* _value) const; - TiXmlElement* - FirstChildElement(const char* _value) { - return const_cast( - (const_cast(this))->FirstChildElement(_value)); - } - -#ifdef TIXML_USE_STL - const TiXmlElement* - FirstChildElement(const std::string& _value) const { - return FirstChildElement(_value.c_str()); - } ///< STL std::string form. - TiXmlElement* - FirstChildElement(const std::string& _value) { - return FirstChildElement(_value.c_str()); - } ///< STL std::string form. -#endif - - /** Query the type (as an enumerated value, above) of this node. - The possible types are: TINYXML_DOCUMENT, TINYXML_ELEMENT, - TINYXML_COMMENT, - TINYXML_UNKNOWN, - TINYXML_TEXT, and TINYXML_DECLARATION. - */ - int - Type() const { - return type; - } - - /** Return a pointer to the Document this node lives in. - Returns null if not in a document. - */ - const TiXmlDocument* GetDocument() const; - TiXmlDocument* - GetDocument() { - return const_cast((const_cast(this))->GetDocument()); - } - - /// Returns true if this node has no children. - bool - NoChildren() const { - return !firstChild; - } - - virtual const TiXmlDocument* - ToDocument() const { - return 0; - } ///< Cast to a more defined type. Will return null if not of the requested - /// type. - virtual const TiXmlElement* - ToElement() const { - return 0; - } ///< Cast to a more defined type. Will return null if not of the requested - /// type. - virtual const TiXmlComment* - ToComment() const { - return 0; - } ///< Cast to a more defined type. Will return null if not of the requested - /// type. - virtual const TiXmlUnknown* - ToUnknown() const { - return 0; - } ///< Cast to a more defined type. Will return null if not of the requested - /// type. - virtual const TiXmlText* - ToText() const { - return 0; - } ///< Cast to a more defined type. Will return null if not of the requested - /// type. - virtual const TiXmlDeclaration* - ToDeclaration() const { - return 0; - } ///< Cast to a more defined type. Will return null if not of the requested - /// type. - - virtual TiXmlDocument* - ToDocument() { - return 0; - } ///< Cast to a more defined type. Will return null if not of the requested - /// type. - virtual TiXmlElement* - ToElement() { - return 0; - } ///< Cast to a more defined type. Will return null if not of the requested - /// type. - virtual TiXmlComment* - ToComment() { - return 0; - } ///< Cast to a more defined type. Will return null if not of the requested - /// type. - virtual TiXmlUnknown* - ToUnknown() { - return 0; - } ///< Cast to a more defined type. Will return null if not of the requested - /// type. - virtual TiXmlText* - ToText() { - return 0; - } ///< Cast to a more defined type. Will return null if not of the requested - /// type. - virtual TiXmlDeclaration* - ToDeclaration() { - return 0; - } ///< Cast to a more defined type. Will return null if not of the requested - /// type. - - /** Create an exact duplicate of this node and return it. The memory must be - deleted - by the caller. - */ - virtual TiXmlNode* Clone() const = 0; - - /** Accept a hierchical visit the nodes in the TinyXML DOM. Every node in the - XML tree will be conditionally visited and the host will be called - back - via the TiXmlVisitor interface. - - This is essentially a SAX interface for TinyXML. (Note however it - doesn't re-parse - the XML for the callbacks, so the performance of TinyXML is unchanged - by using this - interface versus any other.) - - The interface has been based on ideas from: - - - http://www.saxproject.org/ - - http://c2.com/cgi/wiki?HierarchicalVisitorPattern - - Which are both good references for "visiting". - - An example of using Accept(): - @verbatim - TiXmlPrinter printer; - tinyxmlDoc.Accept( &printer ); - const char* xmlcstr = printer.CStr(); - @endverbatim - */ - virtual bool Accept(TiXmlVisitor* visitor) const = 0; - -protected: - TiXmlNode(NodeType _type); - - // Copy to the allocated object. Shared functionality between Clone, Copy - // constructor, - // and the assignment operator. - void CopyTo(TiXmlNode* target) const; - -#ifdef TIXML_USE_STL - // The real work of the input operator. - virtual void StreamIn(std::istream* in, TIXML_STRING* tag) = 0; -#endif - - // Figure out what is at *p, and parse it. Returns null if it is not an xml - // node. - TiXmlNode* Identify(const char* start, TiXmlEncoding encoding); - - TiXmlNode* parent; - NodeType type; - - TiXmlNode* firstChild; - TiXmlNode* lastChild; - - TIXML_STRING value; - - TiXmlNode* prev; - TiXmlNode* next; - -private: - TiXmlNode(const TiXmlNode&); // not implemented. - void operator=(const TiXmlNode& base); // not allowed. -}; - -/** An attribute is a name-value pair. Elements have an arbitrary - number of attributes, each with a unique name. - - @note The attributes are not TiXmlNodes, since they are not - part of the tinyXML document object model. There are other - suggested ways to look at this problem. -*/ -class TiXmlAttribute : public TiXmlBase { - friend class TiXmlAttributeSet; - -public: - /// Construct an empty attribute. - TiXmlAttribute() : TiXmlBase() { - document = 0; - prev = next = 0; - } - -#ifdef TIXML_USE_STL - /// std::string constructor. - TiXmlAttribute(const std::string& _name, const std::string& _value) { - name = _name; - value = _value; - document = 0; - prev = next = 0; - } -#endif - - /// Construct an attribute with a name and value. - TiXmlAttribute(const char* _name, const char* _value) { - name = _name; - value = _value; - document = 0; - prev = next = 0; - } - - const char* - Name() const { - return name.c_str(); - } ///< Return the name of this attribute. - const char* - Value() const { - return value.c_str(); - } ///< Return the value of this attribute. -#ifdef TIXML_USE_STL - const std::string& - ValueStr() const { - return value; - } ///< Return the value of this attribute. -#endif - int IntValue() const; ///< Return the value of this attribute, converted to an integer. - double DoubleValue() const; ///< Return the value of this attribute, converted to a double. - - // Get the tinyxml string representation - const TIXML_STRING& - NameTStr() const { - return name; - } - - /** QueryIntValue examines the value string. It is an alternative to the - IntValue() method with richer error checking. - If the value is an integer, it is stored in 'value' and - the call returns TIXML_SUCCESS. If it is not - an integer, it returns TIXML_WRONG_TYPE. - - A specialized but useful call. Note that for success it returns 0, - which is the opposite of almost all other TinyXml calls. - */ - int QueryIntValue(int* _value) const; - /// QueryDoubleValue examines the value string. See QueryIntValue(). - int QueryDoubleValue(double* _value) const; - - void - SetName(const char* _name) { - name = _name; - } ///< Set the name of this attribute. - void - SetValue(const char* _value) { - value = _value; - } ///< Set the value. - - void SetIntValue(int _value); ///< Set the value from an integer. - void SetDoubleValue(double _value); ///< Set the value from a double. - -#ifdef TIXML_USE_STL - /// STL std::string form. - void - SetName(const std::string& _name) { - name = _name; - } - /// STL std::string form. - void - SetValue(const std::string& _value) { - value = _value; - } -#endif - - /// Get the next sibling attribute in the DOM. Returns null at end. - const TiXmlAttribute* Next() const; - TiXmlAttribute* - Next() { - return const_cast((const_cast(this))->Next()); - } - - /// Get the previous sibling attribute in the DOM. Returns null at beginning. - const TiXmlAttribute* Previous() const; - TiXmlAttribute* - Previous() { - return const_cast((const_cast(this))->Previous()); - } - - bool - operator==(const TiXmlAttribute& rhs) const { - return rhs.name == name; - } - bool - operator<(const TiXmlAttribute& rhs) const { - return name < rhs.name; - } - bool - operator>(const TiXmlAttribute& rhs) const { - return name > rhs.name; - } - - /* Attribute parsing starts: first letter of the name - returns: the next char after the - value end quote - */ - virtual const char* Parse(const char* p, TiXmlParsingData* data, TiXmlEncoding encoding); - - // Prints this Attribute to a FILE stream. - virtual void - Print(FILE* cfile, int depth) const { - Print(cfile, depth, 0); - } - void Print(FILE* cfile, int depth, TIXML_STRING* str) const; - - // [internal use] - // Set the document pointer so the attribute can report errors. - void - SetDocument(TiXmlDocument* doc) { - document = doc; - } - -private: - TiXmlAttribute(const TiXmlAttribute&); // not implemented. - void operator=(const TiXmlAttribute& base); // not allowed. - - TiXmlDocument* document; // A pointer back to a document, for error reporting. - TIXML_STRING name; - TIXML_STRING value; - TiXmlAttribute* prev; - TiXmlAttribute* next; -}; - -/* A class used to manage a group of attributes. - It is only used internally, both by the ELEMENT and the DECLARATION. - - The set can be changed transparent to the Element and Declaration - classes that use it, but NOT transparent to the Attribute - which has to implement a next() and previous() method. Which makes - it a bit problematic and prevents the use of STL. - - This version is implemented with circular lists because: - - I like circular lists - - it demonstrates some independence from the (typical) doubly - linked list. -*/ -class TiXmlAttributeSet { -public: - TiXmlAttributeSet(); - ~TiXmlAttributeSet(); - - void Add(TiXmlAttribute* attribute); - void Remove(TiXmlAttribute* attribute); - - const TiXmlAttribute* - First() const { - return (sentinel.next == &sentinel) ? 0 : sentinel.next; - } - TiXmlAttribute* - First() { - return (sentinel.next == &sentinel) ? 0 : sentinel.next; - } - const TiXmlAttribute* - Last() const { - return (sentinel.prev == &sentinel) ? 0 : sentinel.prev; - } - TiXmlAttribute* - Last() { - return (sentinel.prev == &sentinel) ? 0 : sentinel.prev; - } - - TiXmlAttribute* Find(const char* _name) const; - TiXmlAttribute* FindOrCreate(const char* _name); - -#ifdef TIXML_USE_STL - TiXmlAttribute* Find(const std::string& _name) const; - TiXmlAttribute* FindOrCreate(const std::string& _name); -#endif - -private: - //*ME: Because of hidden/disabled copy-construktor in TiXmlAttribute - //(sentinel-element), - //*ME: this class must be also use a hidden/disabled copy-constructor - TiXmlAttributeSet(const TiXmlAttributeSet&); // not allowed - void operator=(const TiXmlAttributeSet&); // not allowed (as TiXmlAttribute) - - TiXmlAttribute sentinel; -}; - -/** The element is a container class. It has a value, the element name, - and can contain other elements, text, comments, and unknowns. - Elements also contain an arbitrary number of attributes. -*/ -class TiXmlElement : public TiXmlNode { -public: - /// Construct an element. - TiXmlElement(const char* in_value); - -#ifdef TIXML_USE_STL - /// std::string constructor. - TiXmlElement(const std::string& _value); -#endif - - TiXmlElement(const TiXmlElement&); - - TiXmlElement& operator=(const TiXmlElement& base); - - virtual ~TiXmlElement(); - - /** Given an attribute name, Attribute() returns the value - for the attribute of that name, or null if none exists. - */ - const char* Attribute(const char* name) const; - - /** Given an attribute name, Attribute() returns the value - for the attribute of that name, or null if none exists. - If the attribute exists and can be converted to an integer, - the integer value will be put in the return 'i', if 'i' - is non-null. - */ - const char* Attribute(const char* name, int* i) const; - - /** Given an attribute name, Attribute() returns the value - for the attribute of that name, or null if none exists. - If the attribute exists and can be converted to an double, - the double value will be put in the return 'd', if 'd' - is non-null. - */ - const char* Attribute(const char* name, double* d) const; - - /** QueryIntAttribute examines the attribute - it is an alternative to the - Attribute() method with richer error checking. - If the attribute is an integer, it is stored in 'value' and - the call returns TIXML_SUCCESS. If it is not - an integer, it returns TIXML_WRONG_TYPE. If the attribute - does not exist, then TIXML_NO_ATTRIBUTE is returned. - */ - int QueryIntAttribute(const char* name, int* _value) const; - /// QueryUnsignedAttribute examines the attribute - see QueryIntAttribute(). - int QueryUnsignedAttribute(const char* name, unsigned* _value) const; - /** QueryBoolAttribute examines the attribute - see QueryIntAttribute(). - Note that '1', 'true', or 'yes' are considered true, while '0', - 'false' - and 'no' are considered false. - */ - int QueryBoolAttribute(const char* name, bool* _value) const; - /// QueryDoubleAttribute examines the attribute - see QueryIntAttribute(). - int QueryDoubleAttribute(const char* name, double* _value) const; - /// QueryFloatAttribute examines the attribute - see QueryIntAttribute(). - int - QueryFloatAttribute(const char* name, float* _value) const { - double d; - int result = QueryDoubleAttribute(name, &d); - if (result == TIXML_SUCCESS) { *_value = (float)d; } - return result; - } - -#ifdef TIXML_USE_STL - /// QueryStringAttribute examines the attribute - see QueryIntAttribute(). - int - QueryStringAttribute(const char* name, std::string* _value) const { - const char* cstr = Attribute(name); - if (cstr) { - *_value = std::string(cstr); - return TIXML_SUCCESS; - } - return TIXML_NO_ATTRIBUTE; - } - - /** Template form of the attribute query which will try to read the - attribute into the specified type. Very easy, very powerful, but - be careful to make sure to call this with the correct type. - - NOTE: This method doesn't work correctly for 'string' types that - contain spaces. - - @return TIXML_SUCCESS, TIXML_WRONG_TYPE, or TIXML_NO_ATTRIBUTE - */ - template - int - QueryValueAttribute(const std::string& name, T* outValue) const { - const TiXmlAttribute* node = attributeSet.Find(name); - if (!node) return TIXML_NO_ATTRIBUTE; - - std::stringstream sstream(node->ValueStr()); - sstream >> *outValue; - if (!sstream.fail()) return TIXML_SUCCESS; - return TIXML_WRONG_TYPE; - } - - int - QueryValueAttribute(const std::string& name, std::string* outValue) const { - const TiXmlAttribute* node = attributeSet.Find(name); - if (!node) return TIXML_NO_ATTRIBUTE; - *outValue = node->ValueStr(); - return TIXML_SUCCESS; - } -#endif - - /** Sets an attribute of name to a given value. The attribute - will be created if it does not exist, or changed if it does. - */ - void SetAttribute(const char* name, const char* _value); - -#ifdef TIXML_USE_STL - const std::string* Attribute(const std::string& name) const; - const std::string* Attribute(const std::string& name, int* i) const; - const std::string* Attribute(const std::string& name, double* d) const; - int QueryIntAttribute(const std::string& name, int* _value) const; - int QueryDoubleAttribute(const std::string& name, double* _value) const; - - /// STL std::string form. - void SetAttribute(const std::string& name, const std::string& _value); - ///< STL std::string form. - void SetAttribute(const std::string& name, int _value); - ///< STL std::string form. - void SetDoubleAttribute(const std::string& name, double value); -#endif - - /** Sets an attribute of name to a given value. The attribute - will be created if it does not exist, or changed if it does. - */ - void SetAttribute(const char* name, int value); - - /** Sets an attribute of name to a given value. The attribute - will be created if it does not exist, or changed if it does. - */ - void SetDoubleAttribute(const char* name, double value); - - /** Deletes an attribute with the given name. - */ - void RemoveAttribute(const char* name); -#ifdef TIXML_USE_STL - void - RemoveAttribute(const std::string& name) { - RemoveAttribute(name.c_str()); - } ///< STL std::string form. -#endif - - const TiXmlAttribute* - FirstAttribute() const { - return attributeSet.First(); - } ///< Access the first attribute in this element. - TiXmlAttribute* - FirstAttribute() { - return attributeSet.First(); - } - const TiXmlAttribute* - LastAttribute() const { - return attributeSet.Last(); - } ///< Access the last attribute in this element. - TiXmlAttribute* - LastAttribute() { - return attributeSet.Last(); - } - - /** Convenience function for easy access to the text inside an element. - Although easy - and concise, GetText() is limited compared to getting the TiXmlText - child - and accessing it directly. - - If the first child of 'this' is a TiXmlText, the GetText() - returns the character string of the Text node, else null is returned. - - This is a convenient method for getting the text of simple contained - text: - @verbatim - This is text - const char* str = fooElement->GetText(); - @endverbatim - - 'str' will be a pointer to "This is text". - - Note that this function can be misleading. If the element foo was - created from - this XML: - @verbatim - This is text - @endverbatim - - then the value of str would be null. The first child node isn't a text - node, it is - another element. From this XML: - @verbatim - This is text - @endverbatim - GetText() will return "This is ". - - WARNING: GetText() accesses a child node - don't become confused with - the - similarly named TiXmlHandle::Text() and - TiXmlNode::ToText() which are - safe type casts on the referenced node. - */ - const char* GetText() const; - - /// Creates a new Element and returns it - the returned element is a copy. - virtual TiXmlNode* Clone() const; - // Print the Element to a FILE stream. - virtual void Print(FILE* cfile, int depth) const; - - /* Attribtue parsing starts: next char past '<' - returns: next char past '>' - */ - virtual const char* Parse(const char* p, TiXmlParsingData* data, TiXmlEncoding encoding); - - virtual const TiXmlElement* - ToElement() const { - return this; - } ///< Cast to a more defined type. Will return null not of the requested - /// type. - virtual TiXmlElement* - ToElement() { - return this; - } ///< Cast to a more defined type. Will return null not of the requested - /// type. - - /** Walk the XML tree visiting this node and all of its children. - */ - virtual bool Accept(TiXmlVisitor* visitor) const; - -protected: - void CopyTo(TiXmlElement* target) const; - void ClearThis(); // like clear, but initializes 'this' object as well - -// Used to be public [internal use] -#ifdef TIXML_USE_STL - virtual void StreamIn(std::istream* in, TIXML_STRING* tag); -#endif - /* [internal use] - Reads the "value" of the element -- another element, or text. - This should terminate with the current end tag. - */ - const char* ReadValue(const char* in, TiXmlParsingData* prevData, TiXmlEncoding encoding); - -private: - TiXmlAttributeSet attributeSet; -}; - -/** An XML comment. -*/ -class TiXmlComment : public TiXmlNode { -public: - /// Constructs an empty comment. - TiXmlComment() : TiXmlNode(TiXmlNode::TINYXML_COMMENT) {} - /// Construct a comment from text. - TiXmlComment(const char* _value) : TiXmlNode(TiXmlNode::TINYXML_COMMENT) { SetValue(_value); } - TiXmlComment(const TiXmlComment&); - TiXmlComment& operator=(const TiXmlComment& base); - - virtual ~TiXmlComment() {} - - /// Returns a copy of this Comment. - virtual TiXmlNode* Clone() const; - // Write this Comment to a FILE stream. - virtual void Print(FILE* cfile, int depth) const; - - /* Attribtue parsing starts: at the ! of the !-- - returns: next char past '>' - */ - virtual const char* Parse(const char* p, TiXmlParsingData* data, TiXmlEncoding encoding); - - virtual const TiXmlComment* - ToComment() const { - return this; - } ///< Cast to a more defined type. Will return null not of the requested - /// type. - virtual TiXmlComment* - ToComment() { - return this; - } ///< Cast to a more defined type. Will return null not of the requested - /// type. - - /** Walk the XML tree visiting this node and all of its children. - */ - virtual bool Accept(TiXmlVisitor* visitor) const; - -protected: - void CopyTo(TiXmlComment* target) const; - -// used to be public -#ifdef TIXML_USE_STL - virtual void StreamIn(std::istream* in, TIXML_STRING* tag); -#endif - // virtual void StreamOut( TIXML_OSTREAM * out ) const; - -private: -}; - -/** XML text. A text node can have 2 ways to output the next. "normal" output - and CDATA. It will default to the mode it was parsed from the XML file - and - you generally want to leave it alone, but you can change the output mode - with - SetCDATA() and query it with CDATA(). -*/ -class TiXmlText : public TiXmlNode { - friend class TiXmlElement; - -public: - /** Constructor for text element. By default, it is treated as - normal, encoded text. If you want it be output as a CDATA text - element, set the parameter _cdata to 'true' - */ - TiXmlText(const char* initValue) : TiXmlNode(TiXmlNode::TINYXML_TEXT) { - SetValue(initValue); - cdata = false; - } - virtual ~TiXmlText() {} - -#ifdef TIXML_USE_STL - /// Constructor. - TiXmlText(const std::string& initValue) : TiXmlNode(TiXmlNode::TINYXML_TEXT) { - SetValue(initValue); - cdata = false; - } -#endif - - TiXmlText(const TiXmlText& copy) : TiXmlNode(TiXmlNode::TINYXML_TEXT) { copy.CopyTo(this); } - TiXmlText& - operator=(const TiXmlText& base) { - base.CopyTo(this); - return *this; - } - - // Write this text object to a FILE stream. - virtual void Print(FILE* cfile, int depth) const; - - /// Queries whether this represents text using a CDATA section. - bool - CDATA() const { - return cdata; - } - /// Turns on or off a CDATA representation of text. - void - SetCDATA(bool _cdata) { - cdata = _cdata; - } - - virtual const char* Parse(const char* p, TiXmlParsingData* data, TiXmlEncoding encoding); - - virtual const TiXmlText* - ToText() const { - return this; - } ///< Cast to a more defined type. Will return null not of the requested - /// type. - virtual TiXmlText* - ToText() { - return this; - } ///< Cast to a more defined type. Will return null not of the requested - /// type. - - /** Walk the XML tree visiting this node and all of its children. - */ - virtual bool Accept(TiXmlVisitor* content) const; - -protected: - /// [internal use] Creates a new Element and returns it. - virtual TiXmlNode* Clone() const; - void CopyTo(TiXmlText* target) const; - - bool Blank() const; // returns true if all white space and new lines -// [internal use] -#ifdef TIXML_USE_STL - virtual void StreamIn(std::istream* in, TIXML_STRING* tag); -#endif - -private: - bool cdata; // true if this should be input and output as a CDATA style text - // element -}; - -/** In correct XML the declaration is the first entry in the file. - @verbatim - - @endverbatim - - TinyXml will happily read or write files without a declaration, - however. There are 3 possible attributes to the declaration: - version, encoding, and standalone. - - Note: In this version of the code, the attributes are - handled as special cases, not generic attributes, simply - because there can only be at most 3 and they are always the same. -*/ -class TiXmlDeclaration : public TiXmlNode { -public: - /// Construct an empty declaration. - TiXmlDeclaration() : TiXmlNode(TiXmlNode::TINYXML_DECLARATION) {} - -#ifdef TIXML_USE_STL - /// Constructor. - TiXmlDeclaration(const std::string& _version, - const std::string& _encoding, - const std::string& _standalone); -#endif - - /// Construct. - TiXmlDeclaration(const char* _version, const char* _encoding, const char* _standalone); - - TiXmlDeclaration(const TiXmlDeclaration& copy); - TiXmlDeclaration& operator=(const TiXmlDeclaration& copy); - - virtual ~TiXmlDeclaration() {} - - /// Version. Will return an empty string if none was found. - const char* - Version() const { - return version.c_str(); - } - /// Encoding. Will return an empty string if none was found. - const char* - Encoding() const { - return encoding.c_str(); - } - /// Is this a standalone document? - const char* - Standalone() const { - return standalone.c_str(); - } - - /// Creates a copy of this Declaration and returns it. - virtual TiXmlNode* Clone() const; - // Print this declaration to a FILE stream. - virtual void Print(FILE* cfile, int depth, TIXML_STRING* str) const; - virtual void - Print(FILE* cfile, int depth) const { - Print(cfile, depth, 0); - } - - virtual const char* Parse(const char* p, TiXmlParsingData* data, TiXmlEncoding encoding); - - virtual const TiXmlDeclaration* - ToDeclaration() const { - return this; - } ///< Cast to a more defined type. Will return null not of the requested - /// type. - virtual TiXmlDeclaration* - ToDeclaration() { - return this; - } ///< Cast to a more defined type. Will return null not of the requested - /// type. - - /** Walk the XML tree visiting this node and all of its children. - */ - virtual bool Accept(TiXmlVisitor* visitor) const; - -protected: - void CopyTo(TiXmlDeclaration* target) const; -// used to be public -#ifdef TIXML_USE_STL - virtual void StreamIn(std::istream* in, TIXML_STRING* tag); -#endif - -private: - TIXML_STRING version; - TIXML_STRING encoding; - TIXML_STRING standalone; -}; - -/** Any tag that tinyXml doesn't recognize is saved as an - unknown. It is a tag of text, but should not be modified. - It will be written back to the XML, unchanged, when the file - is saved. - - DTD tags get thrown into TiXmlUnknowns. -*/ -class TiXmlUnknown : public TiXmlNode { -public: - TiXmlUnknown() : TiXmlNode(TiXmlNode::TINYXML_UNKNOWN) {} - virtual ~TiXmlUnknown() {} - - TiXmlUnknown(const TiXmlUnknown& copy) : TiXmlNode(TiXmlNode::TINYXML_UNKNOWN) { - copy.CopyTo(this); - } - TiXmlUnknown& - operator=(const TiXmlUnknown& copy) { - copy.CopyTo(this); - return *this; - } - - /// Creates a copy of this Unknown and returns it. - virtual TiXmlNode* Clone() const; - // Print this Unknown to a FILE stream. - virtual void Print(FILE* cfile, int depth) const; - - virtual const char* Parse(const char* p, TiXmlParsingData* data, TiXmlEncoding encoding); - - virtual const TiXmlUnknown* - ToUnknown() const { - return this; - } ///< Cast to a more defined type. Will return null not of the requested - /// type. - virtual TiXmlUnknown* - ToUnknown() { - return this; - } ///< Cast to a more defined type. Will return null not of the requested - /// type. - - /** Walk the XML tree visiting this node and all of its children. - */ - virtual bool Accept(TiXmlVisitor* content) const; - -protected: - void CopyTo(TiXmlUnknown* target) const; - -#ifdef TIXML_USE_STL - virtual void StreamIn(std::istream* in, TIXML_STRING* tag); -#endif - -private: -}; - -/** Always the top level node. A document binds together all the - XML pieces. It can be saved, loaded, and printed to the screen. - The 'value' of a document node is the xml file name. -*/ -class TiXmlDocument : public TiXmlNode { -public: - /// Create an empty document, that has no name. - TiXmlDocument(); - /// Create a document with a name. The name of the document is also the - /// filename of the xml. - TiXmlDocument(const char* documentName); - -#ifdef TIXML_USE_STL - /// Constructor. - TiXmlDocument(const std::string& documentName); -#endif - - TiXmlDocument(const TiXmlDocument& copy); - TiXmlDocument& operator=(const TiXmlDocument& copy); - - virtual ~TiXmlDocument() {} - - /** Load a file using the current document value. - Returns true if successful. Will delete any existing - document data before loading. - */ - bool LoadFile(TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING); - /// Save a file using the current document value. Returns true if successful. - bool SaveFile() const; - /// Load a file using the given filename. Returns true if successful. - bool LoadFile(const char* filename, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING); - /// Save a file using the given filename. Returns true if successful. - bool SaveFile(const char* filename) const; - /** Load a file using the given FILE*. Returns true if successful. Note that - this method - doesn't stream - the entire object pointed at by the FILE* - will be interpreted as an XML file. TinyXML doesn't stream in XML from - the current - file location. Streaming may be added in the future. - */ - bool LoadFile(FILE*, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING); - /// Save a file using the given FILE*. Returns true if successful. - bool SaveFile(FILE*) const; - -#ifdef TIXML_USE_STL - bool - LoadFile(const std::string& filename, - TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING) ///< STL std::string version. - { - return LoadFile(filename.c_str(), encoding); - } - bool - SaveFile(const std::string& filename) const ///< STL std::string version. - { - return SaveFile(filename.c_str()); - } -#endif - - /** Parse the given null terminated block of xml data. Passing in an encoding - to this - method (either TIXML_ENCODING_LEGACY or TIXML_ENCODING_UTF8 will force - TinyXml - to use that encoding, regardless of what TinyXml might otherwise try - to detect. - */ - virtual const char* Parse(const char* p, - TiXmlParsingData* data = 0, - TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING); - - /** Get the root element -- the only top level element -- of the document. - In well formed XML, there should only be one. TinyXml is tolerant of - multiple elements at the document level. - */ - const TiXmlElement* - RootElement() const { - return FirstChildElement(); - } - TiXmlElement* - RootElement() { - return FirstChildElement(); - } - - /** If an error occurs, Error will be set to true. Also, - - The ErrorId() will contain the integer identifier of the error (not - generally useful) - - The ErrorDesc() method will return the name of the error. (very - useful) - - The ErrorRow() and ErrorCol() will return the location of the error - (if known) - */ - bool - Error() const { - return error; - } - - /// Contains a textual (english) description of the error if one occurs. - const char* - ErrorDesc() const { - return errorDesc.c_str(); - } - - /** Generally, you probably want the error string ( ErrorDesc() ). But if you - prefer the ErrorId, this function will fetch it. - */ - int - ErrorId() const { - return errorId; - } - - /** Returns the location (if known) of the error. The first column is column - 1, - and the first row is row 1. A value of 0 means the row and column - wasn't applicable - (memory errors, for example, have no row/column) or the parser lost - the error. (An - error in the error reporting, in that case.) - - @sa SetTabSize, Row, Column - */ - int - ErrorRow() const { - return errorLocation.row + 1; - } - int - ErrorCol() const { - return errorLocation.col + 1; - } ///< The column where the error occured. See ErrorRow() - - /** SetTabSize() allows the error reporting functions (ErrorRow() and - ErrorCol()) - to report the correct values for row and column. It does not change - the output - or input in any way. - - By calling this method, with a tab size - greater than 0, the row and column of each node and attribute is - stored - when the file is loaded. Very useful for tracking the DOM back in to - the source file. - - The tab size is required for calculating the location of nodes. If not - set, the default of 4 is used. The tabsize is set per document. - Setting - the tabsize to 0 disables row/column tracking. - - Note that row and column tracking is not supported when using - operator>>. - - The tab size needs to be enabled before the parse or load. Correct - usage: - @verbatim - TiXmlDocument doc; - doc.SetTabSize( 8 ); - doc.Load( "myfile.xml" ); - @endverbatim - - @sa Row, Column - */ - void - SetTabSize(int _tabsize) { - tabsize = _tabsize; - } - - int - TabSize() const { - return tabsize; - } - - /** If you have handled the error, it can be reset with this call. The error - state is automatically cleared if you Parse a new XML block. - */ - void - ClearError() { - error = false; - errorId = 0; - errorDesc = ""; - errorLocation.row = errorLocation.col = 0; - // errorLocation.last = 0; - } - - /** Write the document to standard out using formatted printing ("pretty - * print"). */ - void - Print() const { - Print(stdout, 0); - } - - /* Write the document to a string using formatted printing ("pretty print"). - This - will allocate a character array (new char[]) and return it as a - pointer. The - calling code pust call delete[] on the return char* to avoid a memory - leak. - */ - // char* PrintToMemory() const; - - /// Print this Document to a FILE stream. - virtual void Print(FILE* cfile, int depth = 0) const; - // [internal use] - void SetError(int err, - const char* errorLocation, - TiXmlParsingData* prevData, - TiXmlEncoding encoding); - - virtual const TiXmlDocument* - ToDocument() const { - return this; - } ///< Cast to a more defined type. Will return null not of the requested - /// type. - virtual TiXmlDocument* - ToDocument() { - return this; - } ///< Cast to a more defined type. Will return null not of the requested - /// type. - - /** Walk the XML tree visiting this node and all of its children. - */ - virtual bool Accept(TiXmlVisitor* content) const; - -protected: - // [internal use] - virtual TiXmlNode* Clone() const; -#ifdef TIXML_USE_STL - virtual void StreamIn(std::istream* in, TIXML_STRING* tag); -#endif - -private: - void CopyTo(TiXmlDocument* target) const; - - bool error; - int errorId; - TIXML_STRING errorDesc; - int tabsize; - TiXmlCursor errorLocation; - bool useMicrosoftBOM; // the UTF-8 BOM were found when read. Note this, and - // try to write. -}; - -/** - A TiXmlHandle is a class that wraps a node pointer with null checks; - this is - an incredibly useful thing. Note that TiXmlHandle is not part of the - TinyXml - DOM structure. It is a separate utility class. - - Take an example: - @verbatim - - - - - - - @endverbatim - - Assuming you want the value of "attributeB" in the 2nd "Child" element, - it's very - easy to write a *lot* of code that looks like: - - @verbatim - TiXmlElement* root = document.FirstChildElement( "Document" ); - if ( root ) - { - TiXmlElement* element = root->FirstChildElement( "Element" ); - if ( element ) - { - TiXmlElement* child = element->FirstChildElement( - "Child" ); - if ( child ) - { - TiXmlElement* child2 = - child->NextSiblingElement( "Child" ); - if ( child2 ) - { - // Finally do something useful. - @endverbatim - - And that doesn't even cover "else" cases. TiXmlHandle addresses the - verbosity - of such code. A TiXmlHandle checks for null pointers so it is - perfectly safe - and correct to use: - - @verbatim - TiXmlHandle docHandle( &document ); - TiXmlElement* child2 = docHandle.FirstChild( "Document" ).FirstChild( - "Element" ).Child( "Child", 1 ).ToElement(); - if ( child2 ) - { - // do something useful - @endverbatim - - Which is MUCH more concise and useful. - - It is also safe to copy handles - internally they are nothing more than - node pointers. - @verbatim - TiXmlHandle handleCopy = handle; - @endverbatim - - What they should not be used for is iteration: - - @verbatim - int i=0; - while ( true ) - { - TiXmlElement* child = docHandle.FirstChild( "Document" - ).FirstChild( "Element" ).Child( "Child", i ).ToElement(); - if ( !child ) - break; - // do something - ++i; - } - @endverbatim - - It seems reasonable, but it is in fact two embedded while loops. The - Child method is - a linear walk to find the element, so this code would iterate much more - than it needs - to. Instead, prefer: - - @verbatim - TiXmlElement* child = docHandle.FirstChild( "Document" ).FirstChild( - "Element" ).FirstChild( "Child" ).ToElement(); - - for( child; child; child=child->NextSiblingElement() ) - { - // do something - } - @endverbatim -*/ -class TiXmlHandle { -public: - /// Create a handle from any node (at any depth of the tree.) This can be a - /// null pointer. - TiXmlHandle(TiXmlNode* _node) { this->node = _node; } - /// Copy constructor - TiXmlHandle(const TiXmlHandle& ref) { this->node = ref.node; } - TiXmlHandle - operator=(const TiXmlHandle& ref) { - if (&ref != this) this->node = ref.node; - return *this; - } - - /// Return a handle to the first child node. - TiXmlHandle FirstChild() const; - /// Return a handle to the first child node with the given name. - TiXmlHandle FirstChild(const char* value) const; - /// Return a handle to the first child element. - TiXmlHandle FirstChildElement() const; - /// Return a handle to the first child element with the given name. - TiXmlHandle FirstChildElement(const char* value) const; - - /** Return a handle to the "index" child with the given name. - The first child is 0, the second 1, etc. - */ - TiXmlHandle Child(const char* value, int index) const; - /** Return a handle to the "index" child. - The first child is 0, the second 1, etc. - */ - TiXmlHandle Child(int index) const; - /** Return a handle to the "index" child element with the given name. - The first child element is 0, the second 1, etc. Note that only - TiXmlElements - are indexed: other types are not counted. - */ - TiXmlHandle ChildElement(const char* value, int index) const; - /** Return a handle to the "index" child element. - The first child element is 0, the second 1, etc. Note that only - TiXmlElements - are indexed: other types are not counted. - */ - TiXmlHandle ChildElement(int index) const; - -#ifdef TIXML_USE_STL - TiXmlHandle - FirstChild(const std::string& _value) const { - return FirstChild(_value.c_str()); - } - TiXmlHandle - FirstChildElement(const std::string& _value) const { - return FirstChildElement(_value.c_str()); - } - - TiXmlHandle - Child(const std::string& _value, int index) const { - return Child(_value.c_str(), index); - } - TiXmlHandle - ChildElement(const std::string& _value, int index) const { - return ChildElement(_value.c_str(), index); - } -#endif - - /** Return the handle as a TiXmlNode. This may return null. - */ - TiXmlNode* - ToNode() const { - return node; - } - /** Return the handle as a TiXmlElement. This may return null. - */ - TiXmlElement* - ToElement() const { - return ((node && node->ToElement()) ? node->ToElement() : 0); - } - /** Return the handle as a TiXmlText. This may return null. - */ - TiXmlText* - ToText() const { - return ((node && node->ToText()) ? node->ToText() : 0); - } - /** Return the handle as a TiXmlUnknown. This may return null. - */ - TiXmlUnknown* - ToUnknown() const { - return ((node && node->ToUnknown()) ? node->ToUnknown() : 0); - } - - /** @deprecated use ToNode. - Return the handle as a TiXmlNode. This may return null. - */ - TiXmlNode* - Node() const { - return ToNode(); - } - /** @deprecated use ToElement. - Return the handle as a TiXmlElement. This may return null. - */ - TiXmlElement* - Element() const { - return ToElement(); - } - /** @deprecated use ToText() - Return the handle as a TiXmlText. This may return null. - */ - TiXmlText* - Text() const { - return ToText(); - } - /** @deprecated use ToUnknown() - Return the handle as a TiXmlUnknown. This may return null. - */ - TiXmlUnknown* - Unknown() const { - return ToUnknown(); - } - -private: - TiXmlNode* node; -}; - -/** Print to memory functionality. The TiXmlPrinter is useful when you need to: - - -# Print to memory (especially in non-STL mode) - -# Control formatting (line endings, etc.) - - When constructed, the TiXmlPrinter is in its default "pretty printing" - mode. - Before calling Accept() you can call methods to control the printing - of the XML document. After TiXmlNode::Accept() is called, the printed - document can - be accessed via the CStr(), Str(), and Size() methods. - - TiXmlPrinter uses the Visitor API. - @verbatim - TiXmlPrinter printer; - printer.SetIndent( "\t" ); - - doc.Accept( &printer ); - fprintf( stdout, "%s", printer.CStr() ); - @endverbatim -*/ -class TiXmlPrinter : public TiXmlVisitor { -public: - TiXmlPrinter() : depth(0), simpleTextPrint(false), buffer(), indent(" "), lineBreak("\n") {} - - virtual bool VisitEnter(const TiXmlDocument& doc); - virtual bool VisitExit(const TiXmlDocument& doc); - - virtual bool VisitEnter(const TiXmlElement& element, const TiXmlAttribute* firstAttribute); - virtual bool VisitExit(const TiXmlElement& element); - - virtual bool Visit(const TiXmlDeclaration& declaration); - virtual bool Visit(const TiXmlText& text); - virtual bool Visit(const TiXmlComment& comment); - virtual bool Visit(const TiXmlUnknown& unknown); - - /** Set the indent characters for printing. By default 4 spaces - but tab (\t) is also useful, or null/empty string for no indentation. - */ - void - SetIndent(const char* _indent) { - indent = _indent ? _indent : ""; - } - /// Query the indention string. - const char* - Indent() { - return indent.c_str(); - } - /** Set the line breaking string. By default set to newline (\n). - Some operating systems prefer other characters, or can be - set to the null/empty string for no indenation. - */ - void - SetLineBreak(const char* _lineBreak) { - lineBreak = _lineBreak ? _lineBreak : ""; - } - /// Query the current line breaking string. - const char* - LineBreak() { - return lineBreak.c_str(); - } - - /** Switch over to "stream printing" which is the most dense formatting - without - linebreaks. Common when the XML is needed for network transmission. - */ - void - SetStreamPrinting() { - indent = ""; - lineBreak = ""; - } - /// Return the result. - const char* - CStr() { - return buffer.c_str(); - } - /// Return the length of the result string. - size_t - Size() { - return buffer.size(); - } - -#ifdef TIXML_USE_STL - /// Return the result. - const std::string& - Str() { - return buffer; - } -#endif - -private: - void - DoIndent() { - for (int i = 0; i < depth; ++i) buffer += indent; - } - void - DoLineBreak() { - buffer += lineBreak; - } - - int depth; - bool simpleTextPrint; - TIXML_STRING buffer; - TIXML_STRING indent; - TIXML_STRING lineBreak; -}; - -#ifdef _MSC_VER -#pragma warning(pop) -#endif - -#endif diff --git a/cameradar_standalone/src/cachemanager.cpp b/cameradar_standalone/src/cachemanager.cpp deleted file mode 100644 index 61aa8d9..0000000 --- a/cameradar_standalone/src/cachemanager.cpp +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright 2016 Etix Labs -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "cachemanager.h" // for cache_manager -#include // for move -#include // for dlerror, dlclose, dlopen, dlsym, etc -#include // for LOG_ERR_ -#include // for bool, false, true - -#include - -namespace etix { - -namespace cameradar { - -#ifdef __APPLE__ -const std::string cache_manager::PLUGIN_EXT = ".dylib"; -#elif __linux__ -const std::string cache_manager::PLUGIN_EXT = ".so"; -#endif - -const std::string cache_manager::default_symbol = "cache_manager_instance_new"; - -cache_manager::cache_manager(const std::string& path, - const std::string& name, - const std::string& symbol) -: name(name), path(path), symbol(symbol), handle(nullptr), ptr(nullptr) {} - -cache_manager::cache_manager(cache_manager&& old) -: path(std::move(old.path)), symbol(std::move(old.symbol)) { - this->handle = old.handle; - old.handle = nullptr; - this->ptr = old.ptr; - old.ptr = nullptr; -} - -cache_manager::~cache_manager() { - delete this->ptr; - if (this->handle) { dlclose(handle); } -} - -bool -cache_manager::make_instance() { - cache_manager_iface* (*new_fn)() = nullptr; - - // Gets the path to the dynamic library - auto real_path = this->make_full_path(); - - // Opens it to get the handle - this->handle = dlopen(real_path.c_str(), RTLD_LAZY); - if (this->handle == nullptr) { - std::cout << "error: " << dlerror() << std::endl; - LOG_ERR_("Failed to load cache manager: " + this->name + ", invalid path", - "cache manager loader"); - return false; - } else { - // Gets the symbol and checks if the library is valid - *(void**)(&new_fn) = dlsym(this->handle, symbol.c_str()); - if (dlerror() != nullptr) { - LOG_ERR_("Invalid cache manager package: " + this->name, "cache manager loader"); - return false; - } - } - - // Returns a string containing the most recent dl* error - dlerror(); - - // Instantiates the cache manager - this->ptr = (*new_fn)(); - if (this->ptr == nullptr) { - LOG_ERR_("Invalid cache manager format: " + this->name, "cache manager loader"); - return false; - } - - return true; -} - -// Generates a path as such : /libdumb_cache_manager.so -std::string -cache_manager::make_full_path() { - std::string full_path = this->path; - full_path += "/lib"; - full_path += this->name; - full_path += "_cache_manager"; - full_path += PLUGIN_EXT; - - return full_path; -} - -cache_manager_iface* cache_manager::operator->() { return this->ptr; } - -const cache_manager_iface* cache_manager::operator->() const { return this->ptr; } - -bool -operator==(std::nullptr_t nullp, const cache_manager& p) { - return p.ptr == nullp; -} - -bool -operator==(const cache_manager& p, std::nullptr_t nullp) { - return p.ptr == nullp; -} - -bool -operator!=(std::nullptr_t nullp, const cache_manager& p) { - return p.ptr != nullp; -} - -bool -operator!=(const cache_manager& p, std::nullptr_t nullp) { - return p.ptr != nullp; -} - -cache_manager_base& -cache_manager_base::get_instance() { - return *this; -} - -} // cameradar - -} // etix diff --git a/cameradar_standalone/src/configuration.cpp b/cameradar_standalone/src/configuration.cpp deleted file mode 100644 index c7018ab..0000000 --- a/cameradar_standalone/src/configuration.cpp +++ /dev/null @@ -1,238 +0,0 @@ -// Copyright 2016 Etix Labs -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include // configuration -#include // std::ifstream -#include // access, F_OK - -namespace etix { - -namespace cameradar { - -const std::string configuration::name_ = "configuration"; - -// Read a file at the path "path" -// If the file is available we return the whole content as -// an std::string inside a pair -// otherwise return false and an empty string inside a pair -std::pair -read_file(const std::string& path) { - auto line = std::string{}; - auto content = std::string{}; - auto file = std::ifstream{ path }; - - if (file.is_open()) { - while (getline(file, line)) { content += line + "\n"; } - file.close(); - } else { - return std::make_pair(false, std::string{}); - } - - return std::make_pair(true, content); -} - -// Loads the IDS dictionary -bool -configuration::load_ids() { - std::string content; - - LOG_DEBUG_("Trying to open ids file from " + this->rtsp_ids_file, "configuration"); - if (this->rtsp_ids_file.size()) { - content = read_file(this->rtsp_ids_file.c_str()).second; - } else { - LOG_WARN_( - "No ids file detected in your configuration, Cameradar will use " - "the default one " - "instead.", - "configuration"); - content = read_file(default_rtsp_ids_file).second; - } - if (content.size()) { - auto root = Json::Value(); - auto reader = Json::Reader(); - reader.parse(content, root); - - for (unsigned int i = 0; i < root["username"].size(); i++) { - if (not root["username"][i].isString()) { - LOG_ERR_("\"username\" should be of type string", "configuration"); - return false; - } - this->usernames.push_back(root["username"][i].asString()); - } - for (unsigned int i = 0; i < root["password"].size(); i++) { - if (not root["password"][i].isString()) { - LOG_ERR_("\"password\" should be of type string", "configuration"); - return false; - } - this->passwords.push_back(root["password"][i].asString()); - } - return true; - } else { - LOG_ERR_( - "Could not load ids file. Make sure you provided a valid path in your " - "configuration file.", - "configuration"); - return false; - } -} - -// Loads the URL dictionary -bool -configuration::load_url() { - std::string content; - - LOG_DEBUG_("Trying to open url file from " + this->rtsp_url_file, "configuration"); - if (this->rtsp_url_file.size()) { - content = read_file(this->rtsp_url_file.c_str()).second; - } else { - LOG_WARN_( - "No url file detected in your configuration, Cameradar will use " - "the default one " - "instead.", - "configuration"); - content = read_file(default_rtsp_url_file).second; - } - if (content.size()) { - auto root = Json::Value(); - auto reader = Json::Reader(); - reader.parse(content, root); - - for (unsigned int i = 0; i < root["urls"].size(); i++) { - if (not root["urls"][i].isString()) { - LOG_ERR_("\"urls\" should be of type string", "configuration"); - return false; - } - this->paths.push_back(root["urls"][i].asString()); - } - - return true; - } else { - LOG_ERR_( - "Could not load ids file. Make sure you provided a valid path in your " - "configuration file.", - "configuration"); - return false; - } -} - -std::pair -serialize(const Json::Value& root) { - std::pair ret; - - try { - if (!root["ports"].isNull()) - ret.second.ports = root["ports"].asString(); - else - ret.second.ports = default_ports; - - if (!root["target"].isNull()) - ret.second.target = root["target"].asString(); - else - ret.second.target = default_target; - - if (!root["rtsp_ids_file"].isNull()) - ret.second.rtsp_ids_file = root["rtsp_ids_file"].asString(); - else - ret.second.rtsp_ids_file = default_rtsp_ids_file; - - if (!root["rtsp_url_file"].isNull()) - ret.second.rtsp_url_file = root["rtsp_url_file"].asString(); - else - ret.second.rtsp_url_file = default_rtsp_url_file; - - if (!root["thumbnail_storage_path"].isNull()) - ret.second.thumbnail_storage_path = root["thumbnail_storage_path"].asString(); - else - ret.second.thumbnail_storage_path = default_thumbnail_storage_path; - - if (!root["cache_manager_path"].isNull()) - ret.second.cache_manager_path = root["cache_manager_path"].asString(); - else - ret.second.cache_manager_path = default_cache_manager_path; - - if (!root["cache_manager_name"].isNull()) - ret.second.cache_manager_name = root["cache_manager_name"].asString(); - else - ret.second.cache_manager_name = default_cache_manager_name; - - ret.first = true; - } catch (const std::exception& e) { - LOG_ERR_("Configuration failed : " + std::string(e.what()), "configuration"); - ret.first = false; - } - - return ret; -} - -Json::Value -configuration::get_raw() const { - return this->raw_conf; -} - -// Loads the configuration from a path -// Returns a pair containing a boolean value & the configuration. -// Will return true & valid configuration if success -// Otherwise false & empty configuration -std::pair -load(const std::pair& args) { - std::string path; - - if (not args.second.exist("-c")) { - path = etix::cameradar::default_configuration_path; - LOG_WARN_("No custom path set, trying to use default path: " + path, "main"); - } else { - path = args.second["-c"]; - } - - // Check if the file exists at the given path - if (access(path.c_str(), F_OK) == -1) { - LOG_ERR_("Can't access: " + path, "configuration"); - return std::make_pair(false, configuration{}); - } - - // Get the content of the file - auto content = read_file(path); - if (not content.first) { - LOG_ERR_( - "Can't open configuration file, you should check your rights to " - "access the file", - "configuration"); - return std::make_pair(false, configuration{}); - } - - // Parse & validate the json - auto root = Json::Value(); - - auto reader = Json::Reader(); - auto parse_succes = reader.parse(content.second, root); - if (not parse_succes) { - LOG_ERR_("Can't load configuration, invalid json format:\n" + - reader.getFormattedErrorMessages(), - "configuration"); - return std::make_pair(false, configuration{}); - } - // Deserialize the json to a configuration struct - // and return - std::pair conf = serialize(root); - conf.second.raw_conf = root; - conf.first &= conf.second.load_url(); - conf.first &= conf.second.load_ids(); - - if (args.second.exist("-s")) conf.second.target = args.second["-s"]; - if (args.second.exist("-p")) conf.second.target = args.second["-p"]; - - return conf; -} -} -} diff --git a/cameradar_standalone/src/describe.cpp b/cameradar_standalone/src/describe.cpp deleted file mode 100644 index 9f2005f..0000000 --- a/cameradar_standalone/src/describe.cpp +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright 2016 Etix Labs -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include - -namespace etix { -namespace cameradar { - -std::mutex m; - -// Ugly workaround -size_t -write_data(void* buffer, size_t size, size_t nmemb, void* userp) { - // I'm sorry for this - // Forget you ever saw it - (void)userp; - if (not buffer || not size || not nmemb) return 0; - - return size * nmemb; -} - -// Sends a request to the camera using the OPTION method, -// then a DESCRIBE to check for valid IDs -// then another DESCIBE with IDs if an authentication is needed -bool -curl_describe(const std::string& path, bool logs) { - CURL* csession; - CURLcode res; - struct curl_slist* custom_msg = NULL; - char URL[256]; - long rc; - m.lock(); - curl_global_init(0); - m.unlock(); - csession = curl_easy_init(); - if (csession == NULL) return -1; - sprintf(URL, "%s", path.c_str()); - // These are the options for all following cURL requests - // Activate verbose if debug is needed - curl_easy_setopt(csession, CURLOPT_NOSIGNAL, 1); - curl_easy_setopt(csession, CURLOPT_TIMEOUT, 1); - curl_easy_setopt(csession, CURLOPT_NOBODY, 1); - curl_easy_setopt(csession, CURLOPT_URL, URL); - curl_easy_setopt(csession, CURLOPT_RTSP_STREAM_URI, URL); - curl_easy_setopt(csession, CURLOPT_FOLLOWLOCATION, 0); - curl_easy_setopt(csession, CURLOPT_HEADER, 0); - curl_easy_setopt(csession, CURLOPT_VERBOSE, 0); - curl_easy_setopt(csession, CURLOPT_RTSP_REQUEST, CURL_RTSPREQ_OPTIONS); - curl_easy_setopt(csession, CURLOPT_WRITEFUNCTION, write_data); - // This request will handshake the stream's server, it should always return 200 OK - curl_easy_perform(csession); - curl_easy_getinfo(csession, CURLINFO_RESPONSE_CODE, &rc); - custom_msg = curl_slist_append( - custom_msg, "Accept: application/x-rtsp-mh, application/rtsl, application/sdp"); - curl_easy_setopt(csession, CURLOPT_RTSPHEADER, custom_msg); - curl_easy_setopt(csession, CURLOPT_RTSP_REQUEST, CURL_RTSPREQ_DESCRIBE); - // This request will check if the given path is right without the need of encrypted ids - unsigned long pos = path.find("@"); - if (pos != std::string::npos) { - std::string encoded = etix::tool::encode::encode64(path.substr(7, pos - 7)); - custom_msg = - curl_slist_append(custom_msg, std::string("Authorization: Basic " + encoded).c_str()); - curl_easy_setopt(csession, CURLOPT_RTSPHEADER, custom_msg); - curl_easy_setopt(csession, CURLOPT_RTSP_REQUEST, CURL_RTSPREQ_DESCRIBE); - // curl_easy_setopt(csession, CURLOPT_WRITEDATA, protofile); - // This request will check if the given ids are good - curl_easy_perform(csession); // will return 404 if good ids, 401 if bad ids - res = curl_easy_getinfo(csession, CURLINFO_RESPONSE_CODE, &rc); - } else { - curl_easy_perform( - csession); // will return 404 if no ids and bad route, 401 if ids, 200 is all ok - res = curl_easy_getinfo(csession, CURLINFO_RESPONSE_CODE, &rc); - } - - curl_easy_cleanup(csession); - - m.lock(); - curl_global_cleanup(); - m.unlock(); - LOG_DEBUG_("[" + path + "] Response code : " + std::to_string(rc), "describe"); - if (logs) { - // Some cameras return 400 instead of 401, don't know why. - // Some cameras timeout and then curl considers the status as 0 - // GST-RTSP-SERVER returns 404 instead of 401, then 401 instead of 404. - if (rc != 401 && rc != 400 && rc && pos == std::string::npos) - LOG_INFO_("Unprotected camera discovered.", "creds_attack"); - return ((res == CURLE_OK) && rc != 401 && rc != 400 && rc); - } - return ((res == CURLE_OK) && rc != 404 && rc != 400 && rc); -} -} -} diff --git a/cameradar_standalone/src/dispatcher.cpp b/cameradar_standalone/src/dispatcher.cpp deleted file mode 100644 index b6c315c..0000000 --- a/cameradar_standalone/src/dispatcher.cpp +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright 2016 Etix Labs -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "dispatcher.h" - -namespace etix { -namespace cameradar { - -using namespace std::chrono_literals; - -// The main loop of the binary -void -dispatcher::run() { - if (not(*cache)->configure(std::make_shared(conf))) { - LOG_ERR_( - "There was a problem with the cache manager, Cameradar can't work properly without " - "cache management", - "dispatcher"); - return; - } - std::thread worker(&dispatcher::do_stuff, this); - using namespace std::chrono_literals; - - // Catch CTRL+C signal - signal_handler::instance(); - - // Wait for event or end - while (signal_handler::instance().should_stop() not_eq stop_priority::stop && - current != task::finished) { - std::this_thread::sleep_for(30ms); - } - - if (doing_stuff()) { - LOG_INFO_("Waiting for a task to terminate", "dispatcher"); - LOG_INFO_("Press CTRL+C again to force stop", "dispatcher"); - } - - // Waiting for task to cleanup / force stop command - while ((signal_handler::instance().should_stop() not_eq stop_priority::force_stop) and - doing_stuff()) { - std::this_thread::sleep_for(30ms); - } - worker.join(); -} - -// This loop is used to add all the tasks specified in the command line -// And then run them successively -void -dispatcher::do_stuff() { - if (opts.second.exist("-d")) { - queue.push_back(new etix::cameradar::mapping(cache, conf, nmap_output)); - queue.push_back(new etix::cameradar::parsing(cache, conf, nmap_output)); - } - if (opts.second.exist("-b")) { - if (opts.second.exist("--gst-rtsp-server")) { - queue.push_back(new etix::cameradar::path_attack(cache, conf, nmap_output)); - queue.push_back(new etix::cameradar::creds_attack(cache, conf, nmap_output)); - } else { - queue.push_back(new etix::cameradar::creds_attack(cache, conf, nmap_output)); - queue.push_back(new etix::cameradar::path_attack(cache, conf, nmap_output)); - } - } - if (opts.second.exist("-t")) { - queue.push_back(new etix::cameradar::thumbnail(cache, conf, nmap_output)); - } - if (opts.second.exist("-g")) { - queue.push_back(new etix::cameradar::stream_check(cache, conf, nmap_output)); - } - if (!opts.second.exist("-d") && !opts.second.exist("-b") && !opts.second.exist("-t") && - !opts.second.exist("-g")) { - queue.push_back(new etix::cameradar::mapping(cache, conf, nmap_output)); - queue.push_back(new etix::cameradar::parsing(cache, conf, nmap_output)); - if (opts.second.exist("--gst-rtsp-server")) { - queue.push_back(new etix::cameradar::path_attack(cache, conf, nmap_output)); - queue.push_back(new etix::cameradar::creds_attack(cache, conf, nmap_output)); - } else { - queue.push_back(new etix::cameradar::creds_attack(cache, conf, nmap_output)); - queue.push_back(new etix::cameradar::path_attack(cache, conf, nmap_output)); - } - queue.push_back(new etix::cameradar::thumbnail(cache, conf, nmap_output)); - queue.push_back(new etix::cameradar::stream_check(cache, conf, nmap_output)); - } - queue.push_back(new etix::cameradar::print(cache, conf, nmap_output)); - while (queue.size() > 0 && signal_handler::instance().should_stop() == stop_priority::running) { - if (queue.front()->run()) - queue.pop_front(); - else { - LOG_ERR_("An error occured in one of the tasks, Cameradar will now stop.", - "dispatcher"); - break; - } - std::this_thread::sleep_for(30ms); - } - this->current = task::finished; -} -} -} diff --git a/cameradar_standalone/src/encode.cpp b/cameradar_standalone/src/encode.cpp deleted file mode 100644 index 48e49d9..0000000 --- a/cameradar_standalone/src/encode.cpp +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright 2016 Etix Labs -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "encode.h" -#include - -namespace etix { - -namespace tool { - -namespace encode { - -std::string -encode64(const std::string& str_to_encode) { - return base64_encode(reinterpret_cast(str_to_encode.c_str()), - str_to_encode.length()); -} - -static const std::string base64_chars = - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz" - "0123456789+/"; - -static inline bool -is_base64(unsigned char c) { - return (isalnum(c) || (c == '+') || (c == '/')); -} - -/* from external source */ -std::string -base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len) { - std::string ret; - int i = 0; - unsigned char char_array_3[3]; - unsigned char char_array_4[4]; - - while (in_len--) { - char_array_3[i++] = *(bytes_to_encode++); - if (i == 3) { - char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; - char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); - char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); - char_array_4[3] = char_array_3[2] & 0x3f; - - for (i = 0; (i < 4); i++) ret += base64_chars[char_array_4[i]]; - i = 0; - } - } - - int j = 0; - if (i) { - for (int j = i; j < 3; j++) char_array_3[j] = '\0'; - - char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; - char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); - char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); - char_array_4[3] = char_array_3[2] & 0x3f; - - for (j = 0; (j < i + 1); j++) ret += base64_chars[char_array_4[j]]; - - while ((i++ < 3)) ret += '='; - } - - return ret; -} -} -} -} diff --git a/cameradar_standalone/src/launch_command.cpp b/cameradar_standalone/src/launch_command.cpp deleted file mode 100644 index f2c3e7f..0000000 --- a/cameradar_standalone/src/launch_command.cpp +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2016 Etix Labs -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include - -namespace etix { -namespace cameradar { - -// Launches a command and checks for the return value -bool -launch_command(const std::string& cmd) { - int status = system(cmd.c_str()); - if (status < 0) { - LOG_ERR_("Error: " + std::string(strerror(errno)) + "", "dispatcher"); - return false; - } else { - if (WIFEXITED(status)) { - LOG_DEBUG_("Program returned normally, exit code " + - std::to_string(WEXITSTATUS(status)), - "dispatcher"); - return true; - } else - LOG_WARN_("Program exited abnormaly.", "dispatcher"); - } - return false; -} -} -} diff --git a/cameradar_standalone/src/main.cpp b/cameradar_standalone/src/main.cpp deleted file mode 100644 index bdde7e8..0000000 --- a/cameradar_standalone/src/main.cpp +++ /dev/null @@ -1,135 +0,0 @@ -// Copyright 2016 Etix Labs -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "version.h" // versionning -#include // program loop -#include // iostream -#include // parsing opt - -void -print_version() { - std::cout << "Cameradar version " << CAMERADAR_VERSION << std::endl; - std::cout << "Build " << CAMERADAR_VERSION_BUILD << std::endl; -} - -// Command line parsing -std::pair -parse_cmdline(int argc, char* argv[]) { - auto opt_parse = etix::tool::opt_parse{ argc, argv }; - - opt_parse.optional("-s", "Set target (e.g.: `172.16.0.0/24`)", true); - opt_parse.optional("-p", "Set ports (e.g.: `554,8554`)", true); - opt_parse.optional("-c", "Path to the configuration file (-c /path/to/conf)", true); - opt_parse.optional("-l", "Set log level (-l 4 will only show warnings and errors)", true); - opt_parse.optional("-d", "Launch the discovery tool on the given target", false); - opt_parse.optional("-b", "Launch the dictionary attack tool on all discovered devices", false); - opt_parse.optional("-t", "Generate thumbnails from detected cameras", false); - opt_parse.optional("-g", "Check if the stream can be opened with GStreamer", false); - opt_parse.optional("-v", "Display Cameradar's version", false); - opt_parse.optional("-h", "Display this help", false); - opt_parse.optional( - "--gst-rtsp-server", - "Change the order of the attack to match GST RTSP Server's implementation of " - "RTSP. Some cameras and RTSP servers will use this standard instead of the more " - "standard one. For more information, see the README.md file.", - false); - opt_parse.execute(); - - if (opt_parse.exist("-h")) { - opt_parse.print_help(); - return std::make_pair(false, opt_parse); - } else if (opt_parse.exist("-v")) { - print_version(); - return std::make_pair(false, opt_parse); - } else if (opt_parse.has_error()) { - std::cout << "Usage: ./cameradar [option]\n\toptions:\n" << std::endl; - opt_parse.print_help(); - return std::make_pair(false, opt_parse); - } - - return std::make_pair(true, opt_parse); -} - -// Check if a folder exists, is readable and writable -bool -check_folder(const std::string& path) { - struct stat sb; - - if ((stat(path.c_str(), &sb) == 0) && (S_ISDIR(sb.st_mode)) && (sb.st_mode & S_IRUSR) && - (sb.st_mode & S_IWUSR)) { - LOG_INFO_("Folder " + path + " is available and has sufficient rights", "main"); - return true; - } - LOG_ERR_("Folder " + path + " has insufficient rights, please check your configuration", - "main"); - return false; -} - -// Check if the storage path is available -bool -check_storage_path(const std::string& thumbnail_storage_path) { - LOG_INFO_("Checking if storage path exists and are usable", "main"); - return (check_folder(thumbnail_storage_path)); -} - -int -main(int argc, char* argv[]) { - etix::tool::logger::get_instance("cameradar").set_level(etix::tool::loglevel::DEBUG); - auto args = parse_cmdline(argc, argv); - if (not args.first) return EXIT_FAILURE; - - print_version(); - - if (not args.second.exist("-l")) { - LOG_INFO_("No log level set, using log level 1", "main"); - } else { - try { - int level = std::stoi(args.second["-l"]); - etix::tool::logger::get_instance("cameradar") - .set_level(static_cast(level)); - } catch (...) { - LOG_ERR_("Invalid log level format, log level should be 1, 2, 4, 5 or 6", "main"); - return EXIT_FAILURE; - } - } - - // Try to load the configuration - auto conf = etix::cameradar::load(args); - if (not conf.first) { return EXIT_FAILURE; } - - LOG_INFO_("Configuration successfully loaded", "main"); - - // If one of the path is invalid, exit - auto paths_ok = check_storage_path(conf.second.thumbnail_storage_path); - if (not paths_ok) { return EXIT_FAILURE; } - - // Here we should get the cache manager but for now we will juste - // make a dumb cache manager - auto plug = std::make_shared(conf.second.cache_manager_path, - conf.second.cache_manager_name); - - if (not plug || not plug->make_instance()) { - LOG_ERR_(std::string("Invalid cache manager "), "cameradar"); - return false; - } - - LOG_INFO_("Launching Cameradar, press CTRL+C to gracefully stop", "main"); - - etix::cameradar::dispatcher disp(conf.second, plug, args); - - disp.run(); - - LOG_WARN_("See ya !", "cameradar"); - return EXIT_SUCCESS; -} diff --git a/cameradar_standalone/src/opt_parse.cpp b/cameradar_standalone/src/opt_parse.cpp deleted file mode 100644 index 8e3abf8..0000000 --- a/cameradar_standalone/src/opt_parse.cpp +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright 2016 Etix Labs -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "opt_parse.h" -#include - -namespace etix { - -namespace tool { - -opt_parse::opt_parse(int argc, char* argv[]) : argc(argc), argv(argv) {} - -opt_parse::~opt_parse() {} - -void -opt_parse::required(const std::string& name, const std::string& desc, bool need_arg) { - this->params.emplace(name, opt_param(true, need_arg, name, desc)); -} - -void -opt_parse::optional(const std::string& name, const std::string& desc, bool need_arg) { - this->params.emplace(name, opt_param(false, need_arg, name, desc)); -} - -bool -opt_parse::execute() { - int i = 1; - - // if params are invalid - if (this->argc < 1 || not this->argv) { return false; } - - while (i != this->argc) { - // there is less argument than argc - if (not this->argv[i]) { return false; } - auto params = this->params.find(std::string(this->argv[i])); - if (params != this->params.end()) { - this->params_cnt += 1; - (*params).second.is_passed = true; - if ((*params).second.need_arg == true && (i + 1) != this->argc) { - (*params).second.argument = this->argv[i + 1]; - i += 1; - } - } - i += 1; - } - return true; -} - -opt_parse::iterator -opt_parse::begin() const { - std::vector> p; - - for (auto entry : this->params) { - p.push_back(std::make_pair(entry.second.name, entry.second.argument)); - } - return iterator(p, 0); -} - -opt_parse::iterator -opt_parse::end() const { - return iterator(std::vector>(), this->params_cnt); -} - -void -opt_parse::print_usage() const { - std::cout << "Usage: " << this->argv[0]; - - for (auto entry : this->params) { - if (entry.second.required == true) { - if (entry.second.need_arg == true) { std::cout << " "; } - } - } - std::cout << std::endl; -} - -void -opt_parse::print_help() const { - std::cout << "help: " << this->argv[0] << std::endl; - - for (auto entry : this->params) { - std::cout << entry.second.name << " " << entry.second.desc << std::endl; - } -} - -bool -opt_parse::has_error() const { - for (auto entry : this->params) { - // is the parameter required ? - // the parameter need arguement ? - if ((entry.second.required == true && entry.second.is_passed == false) || - (entry.second.is_passed == true && entry.second.need_arg == true && - entry.second.argument == "")) { - return true; - } - } - - return false; -} - -bool -opt_parse::exist(const std::string& opt) const { - auto params = this->params.find(opt); - - if (params == this->params.end()) { return false; } - - return (*params).second.is_passed; -} - -std::string opt_parse::operator[](const std::string& opt) const { - std::string param(""); - - auto opt_param = this->params.find(opt); - if (opt_param != this->params.end()) { param = (*opt_param).second.argument; } - - return param; -} - -} // tool - -} // etix diff --git a/cameradar_standalone/src/rtsp_path.cpp b/cameradar_standalone/src/rtsp_path.cpp deleted file mode 100644 index 6357e8a..0000000 --- a/cameradar_standalone/src/rtsp_path.cpp +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2016 Etix Labs -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include - -namespace etix { - -namespace cameradar { - -const std::string -make_path(const stream_model& model) { - if (model.password != "" || model.username != "") { - std::string ret(model.service_name + "://" + model.username + ":" + model.password + "@" + - model.address + ":" + std::to_string(model.port) + model.route); - LOG_DEBUG_(ret, "debug"); - return ret; - } else { - std::string ret(model.service_name + "://" + model.address + ":" + - std::to_string(model.port) + model.route); - LOG_DEBUG_(ret, "debug"); - return ret; - } -} -} -} diff --git a/cameradar_standalone/src/signal_handler.cpp b/cameradar_standalone/src/signal_handler.cpp deleted file mode 100644 index f773248..0000000 --- a/cameradar_standalone/src/signal_handler.cpp +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2016 Etix Labs -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include - -namespace etix { -namespace cameradar { - -event_handler signal_handler::handler; - -signal_handler::signal_handler() {} - -void -signal_handler::call_handler(int signum) { - handler.handle_signal(signum); -} - -signal_handler& -signal_handler::instance(void) { - static signal_handler singleton; - - struct sigaction sa; - sa.sa_handler = call_handler; - sigemptyset(&sa.sa_mask); - sa.sa_flags = 0; - sigaction(SIGINT, &sa, 0); - - return singleton; -} - -etix::cameradar::stop_priority -signal_handler::should_stop(void) const { - return handler.should_stop(); -} -} -} diff --git a/cameradar_standalone/src/stream_model.cpp b/cameradar_standalone/src/stream_model.cpp deleted file mode 100644 index 63b2f66..0000000 --- a/cameradar_standalone/src/stream_model.cpp +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2016 Etix Labs -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include - -namespace etix { -namespace cameradar { - -Json::Value -deserialize(const stream_model& model) { - Json::Value ret; - - ret["address"] = model.address; - ret["port"] = model.port; - ret["username"] = model.username; - ret["password"] = model.password; - ret["route"] = model.route; - ret["service_name"] = model.service_name; - ret["product"] = model.product; - ret["protocol"] = model.protocol; - ret["state"] = model.state; - ret["path_found"] = model.path_found; - ret["ids_found"] = model.ids_found; - ret["thumbnail_path"] = model.thumbnail_path; - return ret; -} -} -} diff --git a/cameradar_standalone/src/tasks/creds_attack.cpp b/cameradar_standalone/src/tasks/creds_attack.cpp deleted file mode 100644 index f712ff3..0000000 --- a/cameradar_standalone/src/tasks/creds_attack.cpp +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright 2016 Etix Labs -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include - -namespace etix { -namespace cameradar { - -static const std::string no_ids_warning_ = - "The ids.json files' default paths didn't match with the discovered " - "cameras. Either " - "they have custom ids, or your ids.json file does not contain enough " - "default routes. " - "Path dictionary attack is impossible without the credentials."; - -// Tries to match the detected combination of Username / Password -// with the camera stream. Creates a resource in the DB upon -// valid discovery -bool -creds_attack::test_ids(const etix::cameradar::stream_model& stream, - const std::string& password, - const std::string& username) const { - bool found = false; - std::string path = stream.service_name + "://"; - if (username != "" || password != "") { path += username + ":" + password + "@"; } - path += stream.address + ":" + std::to_string(stream.port) + stream.route; - LOG_INFO_("Testing ids : " + path, "creds_attack"); - try { - if (curl_describe(path, true)) { - LOG_INFO_("[FOUND IDS] : " + path, "creds_attack"); - found = true; - stream_model newstream{ - stream.address, stream.port, username, password, - stream.route, stream.service_name, stream.product, stream.protocol, - stream.state, stream.path_found, true, stream.thumbnail_path - }; - if ((*cache)->has_changed(stream)) return true; - (*cache)->update_stream(newstream); - } else { - stream_model newstream{ stream.address, stream.port, username, - password, stream.route, stream.service_name, - stream.product, stream.protocol, stream.state, - stream.path_found, false, stream.thumbnail_path }; - if ((*cache)->has_changed(stream)) return true; - (*cache)->update_stream(newstream); - } - } catch (const std::runtime_error& e) { - LOG_DEBUG_("Ids already tested : " + std::string(e.what()), "creds_attack"); - } - return found; -} - -bool -ids_already_found(std::vector streams, stream_model stream) { - for (const auto& it : streams) { - if ((stream.address == it.address) && (stream.port == it.port) && it.ids_found) return true; - } - return false; -} - -bool -creds_attack::attack_camera_creds(const stream_model& stream) const { - for (const auto& username : conf.usernames) { - if (signal_handler::instance().should_stop() != etix::cameradar::stop_priority::running) - break; - for (const auto& password : conf.passwords) { - if (signal_handler::instance().should_stop() != etix::cameradar::stop_priority::running) - break; - if ((*cache)->has_changed(stream)) return true; - if (test_ids(stream, password, username)) return true; - } - } - return false; -} - -// Tries to discover the right IDs on all RTSP streams in DB -// Uses the ids.json file to try different combinations -bool -creds_attack::run() const { - std::vector> futures; - - LOG_INFO_( - "Beginning attack of the credentials , it may " - "take a while.", - "creds_attack"); - std::vector streams = (*cache)->get_streams(); - LOG_DEBUG_("Found " + std::to_string(streams.size()) + " streams in the cache", "creds_attack"); - size_t found = 0; - for (const auto& stream : streams) { - if (signal_handler::instance().should_stop() != etix::cameradar::stop_priority::running) - break; - if ((found < streams.size()) && ids_already_found(streams, stream)) { - LOG_INFO_(stream.address + - " : This camera's ids were already discovered in " - "the database. Skipping to " - "the next camera.", - "creds_attack"); - ++found; - } else { - futures.push_back( - std::async(std::launch::async, &creds_attack::attack_camera_creds, this, stream)); - } - } - for (auto& fit : futures) { - if (fit.get()) { ++found; } - } - if (!found) { - LOG_WARN_(no_ids_warning_, "creds_attack"); - return false; - } else - LOG_INFO_("Found " + std::to_string(found) + " ids for " + std::to_string(streams.size()) + - " cameras", - "creds_attack"); - return true; -} -} -} diff --git a/cameradar_standalone/src/tasks/mapping.cpp b/cameradar_standalone/src/tasks/mapping.cpp deleted file mode 100644 index ff96f24..0000000 --- a/cameradar_standalone/src/tasks/mapping.cpp +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2016 Etix Labs -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include - -namespace etix { -namespace cameradar { - -// The first command checks if dpkg finds nmap in the system by cutting the -// result and grepping -// nmap from it. -// -// The second command checks the version of nmap, right now it needs to be the -// 6.47 but this could -// be changed to 6 or greater depending on the needs. In a docker container -// this should not be a -// problem. -bool -nmap_is_ok() { - return ( - (system("dpkg -l | cut -c 5-9 | grep nmap") == 0) - && launch_command("mkdir -p /tmp/scans")); // Creates the directory in which the scans will be stored -} - -// Launches and checks the return of the nmap command -// Uses the target specified in the conf file to launch nmap -bool -mapping::run() const { - if (nmap_is_ok()) { - std::string target = this->conf.target; - std::replace(target.begin(), target.end(), ',', ' '); - LOG_INFO_("Nmap 6.0 or greater found", "mapping"); - LOG_INFO_("Beginning mapping task. This may take a while.", "mapping"); - std::string cmd = - "nmap -T4 -A " + target + " -p " + this->conf.ports + " -oX " + nmap_output; - LOG_DEBUG_("Launching nmap : " + cmd, "mapping"); - bool ret = launch_command(cmd); - if (ret) - LOG_INFO_("Nmap XML output successfully generated in file: " + nmap_output, "mapping"); - else - LOG_ERR_("Nmap command failed", "mapping"); - return ret; - } else { - LOG_ERR_("Nmap 6.0 or greater is required to launch Cameradar", "mapping"); - return false; - } -} -} -} diff --git a/cameradar_standalone/src/tasks/parsing.cpp b/cameradar_standalone/src/tasks/parsing.cpp deleted file mode 100644 index 844eaa0..0000000 --- a/cameradar_standalone/src/tasks/parsing.cpp +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright 2016 Etix Labs -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include - -namespace etix { -namespace cameradar { - -static const std::string no_hosts_found_ = - "No hosts were discovered on your network. Please check your internet " - "connexion " - "and verify that the targetworks you specified in your configuration file " - "were " - "accessible"; - -// Avoids segfaults on unknown xml structure -std::string -xml_safe_get(const TiXmlElement* elem, const std::string& attr) { - if (elem == nullptr) return "closed"; - if (elem->Attribute(attr.c_str()) != nullptr) return std::string(elem->Attribute(attr.c_str())); - return "closed"; -} - -// Parse a single host node (generally containing only one camera) -// Pushes it back to the data structure -void -parsing::parse_camera(TiXmlElement* xml_host, std::vector& data) const { - TiXmlElement* xml_streams = xml_host->FirstChild("ports")->ToElement(); - stream_model stream; - for (TiXmlElement* xml_stream = xml_streams->FirstChild("port")->ToElement(); xml_stream; - xml_stream = xml_stream->NextSiblingElement("port")) { - stream.address = xml_safe_get(xml_host->FirstChild("address")->ToElement(), "addr"); - stream.protocol = xml_safe_get(xml_stream, "protocol"); - stream.port = static_cast(std::stoi(xml_safe_get(xml_stream, "portid"))); - TiXmlElement* state = xml_stream->FirstChild("state")->ToElement(); - stream.state = xml_safe_get(state, "state"); - TiXmlElement* service; - if (state->NextSibling("service") && - (service = state->NextSibling("service")->ToElement())) { - stream.service_name = xml_safe_get(service, "name"); - stream.product = xml_safe_get(service, "product"); - } else { - stream.service_name = "closed"; - stream.product = "closed"; - } - if (!stream.state.compare("open")) data.push_back(stream); - } -} - -// Prints all detected cameras into the data structure and stops the program if -// no open RTSP streams were found -bool -parsing::print_detected_cameras(const std::vector& data) const { - int added = 0; - for (const auto& stream : data) { - if (!stream.service_name.compare("rtsp") && !stream.state.compare("open")) { - try { - LOG_INFO_("Generated JSON Result : " + deserialize(stream).toStyledString(), - "print"); - added++; - } catch (const std::runtime_error& e) { - LOG_WARN_("Port already scanned : " + std::string(e.what()), "parsing"); - added++; - } - } - } - if (!added) { - LOG_WARN_( - "Mapping unsuccessful, no rtsp streams were discovered. You " - "should try other " - "targetworks", - "parsing"); - return false; - } - LOG_INFO_("Mapping successfuly ended, " + std::to_string(added) + - " RTSP streams were discovered.", - "parsing"); - (*cache)->set_streams(data); - return true; -} - -// Opens the nmap output file, parses the data of each discovered port -// Adds the RTSP ports only into the DB -bool -parsing::run() const { - std::vector data; - try { - TiXmlDocument doc(nmap_output.c_str()); - doc.LoadFile(); - TiXmlHandle docHandle(&doc); - - TiXmlElement* nmaprun = docHandle.FirstChild("nmaprun").ToElement(); - TiXmlNode* xml_node = nmaprun->FirstChild("host"); - if (xml_node == NULL) return false; - TiXmlElement* xml_host; - if ((xml_host = xml_node->ToElement()) && xml_host->Attribute("endtime")) - for (xml_host = xml_node->ToElement(); xml_host; - xml_host = xml_host->NextSiblingElement("host")) { - parse_camera(xml_host, data); - } - else - LOG_WARN_(no_hosts_found_, "parsing"); - if (data.size() == 0) { LOG_WARN_("No cameras were discovered", "parsing"); } - return print_detected_cameras(data); - } catch (const std::exception& e) { - LOG_ERR_("Error during parsing. path_attack aborted : " + std::string(e.what()), "parsing"); - return false; - } -} -} -} diff --git a/cameradar_standalone/src/tasks/path_attack.cpp b/cameradar_standalone/src/tasks/path_attack.cpp deleted file mode 100644 index b92373f..0000000 --- a/cameradar_standalone/src/tasks/path_attack.cpp +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright (C) 2016 Etix Labs - All Rights Reserved. -// All information contained herein is, and remains the property of Etix Labs -// and its suppliers, -// if any. The intellectual and technical concepts contained herein are -// proprietary to Etix Labs -// Dissemination of this information or reproduction of this material is -// strictly forbidden unless -// prior written permission is obtained from Etix Labs. - -#include - -namespace etix { -namespace cameradar { - -static const std::string no_route_found_ = - "The url.json files' default paths didn't match with the discovered " - "cameras. Either " - "they have a custom path, or your url.json file does not contain enough " - "default " - "routes. Thumbnail generation is impossible without the path."; - -// Tries to match the detected combination of Username / Password -// with a route for the camera stream. Creates a resource in the DB upon -// valid discovery -bool -path_attack::test_path(const stream_model& stream, const std::string& route) const { - bool found = false; - std::string path = stream.service_name + "://" + stream.username + ":" + stream.password + "@" + - stream.address + ":" + std::to_string(stream.port); - if (route.front() != '/') { path += "/"; } - path += route; - LOG_INFO_("Testing path : " + path, "path_attack"); - try { - if (curl_describe(path, false)) { - // insert in DB and go to the next port, print a cool message - found = true; - LOG_INFO_("Discovered a valid path : [" + path + "]", "path_attack"); - stream_model newstream{ - stream.address, stream.port, stream.username, stream.password, route, - stream.service_name, stream.product, stream.protocol, stream.state, true, - stream.ids_found, stream.thumbnail_path - }; - if ((*cache)->has_changed(stream)) return true; - (*cache)->update_stream(newstream); - } else { - stream_model newstream{ - stream.address, stream.port, stream.username, stream.password, route, - stream.service_name, stream.product, stream.protocol, stream.state, false, - stream.ids_found, stream.thumbnail_path - }; - if ((*cache)->has_changed(stream)) return true; - (*cache)->update_stream(newstream); - } - } catch (const std::runtime_error& e) { LOG_INFO_(e.what(), "path_attack"); } - return found; -} - -bool -path_already_found(std::vector streams, stream_model model) { - for (const auto& stream : streams) { - if ((model.address == stream.address) && (model.port == stream.port) && stream.path_found) - return true; - } - return false; -} - -bool -path_attack::attack_camera_path(const stream_model& stream) const { - for (const auto& route : conf.paths) { - if (signal_handler::instance().should_stop() != etix::cameradar::stop_priority::running) - break; - if ((*cache)->has_changed(stream)) return true; - if (test_path(stream, route)) return true; - } - return false; -} - -// Tries to discover a route on all RTSP streams in DB -// Uses the url.json file to try different routes -bool -path_attack::run() const { - std::vector> futures; - - LOG_INFO_("Beginning attack of the camera paths, it may take a while.", "path_attack"); - std::vector streams = (*cache)->get_streams(); - int found = 0; - for (const auto& stream : streams) { - if (signal_handler::instance().should_stop() != etix::cameradar::stop_priority::running) - break; - if (path_already_found(streams, stream)) { - LOG_INFO_(stream.address + - " : This camera's path was already discovered in the database. Skipping " - "to the next camera.", - "path_attack"); - ++found; - } else { - futures.push_back( - std::async(std::launch::async, &path_attack::attack_camera_path, this, stream)); - } - } - for (auto& fit : futures) { - if (fit.get()) { ++found; } - } - if (!found) { - LOG_WARN_(no_route_found_, "path_attack"); - - } else - LOG_INFO_("Found " + std::to_string(found) + " routes for " + - std::to_string(streams.size()) + " cameras", - "path_attack"); - return true; -} -} -} diff --git a/cameradar_standalone/src/tasks/print.cpp b/cameradar_standalone/src/tasks/print.cpp deleted file mode 100644 index bec50ce..0000000 --- a/cameradar_standalone/src/tasks/print.cpp +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2016 Etix Labs -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include - -namespace etix { -namespace cameradar { - -// Launches and checks the return of the nmap command -// Uses the specified targets in the conf file to launch nmap -bool -print::run() const { - std::vector results = (*cache)->get_valid_streams(); - std::ofstream file; - - file.open(default_result_file_path); - if (file.fail()) { - LOG_ERR_("Result file could not be opened : " + default_result_file_path, "print"); - return false; - } - - file << "[\n"; - unsigned int i = 0; - for (const auto& stream : results) { - file << deserialize(stream).toStyledString(); - - if (++i < results.size()) file << ","; - - LOG_INFO_("Generated JSON Result : " + deserialize(stream).toStyledString(), "print"); - } - file << "]"; - file.close(); - return true; -} -} -} diff --git a/cameradar_standalone/src/tasks/stream_check.cpp b/cameradar_standalone/src/tasks/stream_check.cpp deleted file mode 100644 index 1e05145..0000000 --- a/cameradar_standalone/src/tasks/stream_check.cpp +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright 2016 Etix Labs -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include - -namespace etix { -namespace cameradar { - -// Gets all the discovered streams with good routes and logs -// And launches an ffmpeg command to generate a thumbnail -// In order to check for the stream validity -bool -stream_check::run() const { - GstElement* elem; - gst_init(nullptr, nullptr); - std::vector streams = (*cache)->get_valid_streams(); - - if (not streams.size()) { - LOG_WARN_("There were no valid streams to check. Cameradar will stop.", "stream_check"); - return false; - } - - for (const auto& stream : streams) { - GError* error = NULL; - - GstElement* pipeline = - gst_parse_launch("rtspsrc name=source ! rtph264depay ! h264parse ! fakesink", &error); - - std::string location = "rtsp://"; - location += stream.username + ":" + stream.password + "@" + stream.address + ":" + - std::to_string(stream.port); - if (pipeline == NULL) { - LOG_ERR_("[" + stream.address + "] Can't configure pipeline", "stream_check"); - return false; - } else { - elem = gst_bin_get_by_name(GST_BIN(pipeline), "source"); - LOG_DEBUG_("Launching gstreamer check on rtsp://" + stream.username + ":" + - stream.password + "@" + stream.address + ":" + - std::to_string(stream.port), - "gstreamer check"); - g_object_set(G_OBJECT(elem), "location", location.c_str(), "latency", 20, NULL); - - if (gst_element_set_state(pipeline, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) { - LOG_ERR_( - "This stream is unaccessible with GStreamer, there must be a " - "configuration issue", - "stream_check"); - gst_object_unref(pipeline); - stream_model invalidstream{ - stream.address, stream.port, stream.username, stream.password, - stream.route, stream.service_name, stream.product, stream.protocol, - "invalid stream", stream.path_found, stream.ids_found, stream.thumbnail_path - }; - (*cache)->update_stream(invalidstream); - return false; - } - LOG_INFO_("[" + stream.address + - "] This stream is accessible and seems to be functional", - "stream_check"); - } - } - LOG_INFO_("All streams could be accessed with GStreamer", "stream_check"); - return true; -} -} -} diff --git a/cameradar_standalone/src/tasks/thumbnail.cpp b/cameradar_standalone/src/tasks/thumbnail.cpp deleted file mode 100644 index 4ebcc6b..0000000 --- a/cameradar_standalone/src/tasks/thumbnail.cpp +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright 2016 Etix Labs -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include - -namespace etix { -namespace cameradar { - -std::string -remove_trailing_backslash(std::string s) { - while (s.back() == '/') { s.pop_back(); } - return s; -} - -// Tranforms the path into a path for the thumbnail -// Example : -// rtsp://username:password@172.16.100.13/live.sdp -// will become /storage/path/172.16.100.13/1345425533.jpg -std::string -thumbnail::build_output_file_path(const std::string& path) const { - auto ss = std::stringstream{}; - - ss << remove_trailing_backslash(this->conf.thumbnail_storage_path); - ss << "/"; - ss << path; - ss << "/"; - ss << std::to_string(std::chrono::system_clock::to_time_t(std::chrono::system_clock::now())); - ss << ".jpg"; - - return ss.str(); -} - -bool -thumbnail::generate_thumbnail(const stream_model& stream) const { - LOG_INFO_("Generating thumbnail for " + stream.address, "thumbnail_generation"); - if (signal_handler::instance().should_stop() != etix::cameradar::stop_priority::running) - return false; - std::string ffmpeg_cmd = - "mkdir -p %s ; " - "timeout 20 " - "ffmpeg " - "-rtsp_transport tcp " - "-y " - "-nostdin " - "-loglevel quiet " // no logs - "-i '%s' " // input - "-vcodec mjpeg " // jpeg codec - "-vframes 1 " // only take one frame - "-an " // disable audio - "-f image2 " // force image - "-s 240x180 " // force size - "'%s'"; - std::string fullpath = make_path(stream); - std::string output = build_output_file_path(stream.address); - ffmpeg_cmd = tool::fmt(ffmpeg_cmd.c_str(), - output.substr(0, output.find_last_of("/")).c_str(), - fullpath.c_str(), - output.c_str()); - if (!launch_command(ffmpeg_cmd)) { - LOG_WARN_("The following command [" + ffmpeg_cmd + - "] didn't work. That can either mean that the stream is " - "not valid or " - "that there is a problem with the camera.", - "thumbnail_generation"); - return false; - } else { - LOG_DEBUG_("Generated thumbnail : " + ffmpeg_cmd, "thumbnail_generation"); - try { - stream_model result{ stream.address, stream.port, stream.username, - stream.password, stream.route, stream.service_name, - stream.product, stream.protocol, stream.state, - stream.path_found, stream.ids_found, output }; - (*cache)->update_stream(result); - - } catch (const std::exception& e) { LOG_DEBUG_(e.what(), "thumbnail_generation"); } - } - return true; -} - -// Gets all the discovered streams with good routes and logs -// And launches an ffmpeg command to generate a thumbnail -// In order to check for the stream validity -bool -thumbnail::run() const { - std::vector> futures; - std::vector streams = (*cache)->get_valid_streams(); - - LOG_INFO_("Started thumbnail generation, it may take a while", "thumbnail"); - if (not streams.size()) { - LOG_WARN_("There were no valid streams to generate thumbnails from. Cameradar will stop.", - "thumbnail_generation"); - return false; - } - int done = 0; - for (const auto& stream : streams) { - futures.push_back( - std::async(std::launch::async, &thumbnail::generate_thumbnail, this, stream)); - } - for (auto& fit : futures) { - if (fit.get()) { ++done; } - } - return true; -} -} -} diff --git a/cameradar_standalone/src/tinystr.cpp b/cameradar_standalone/src/tinystr.cpp deleted file mode 100644 index d76873b..0000000 --- a/cameradar_standalone/src/tinystr.cpp +++ /dev/null @@ -1,94 +0,0 @@ -/* -www.sourceforge.net/projects/tinyxml - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any -damages arising from the use of this software. - -Permission is granted to anyone to use this software for any -purpose, including commercial applications, and to alter it and -redistribute it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must -not claim that you wrote the original software. If you use this -software in a product, an acknowledgment in the product documentation -would be appreciated but is not required. - -2. Altered source versions must be plainly marked as such, and -must not be misrepresented as being the original software. - -3. This notice may not be removed or altered from any source -distribution. -*/ - -#ifndef TIXML_USE_STL - -#include "tinystr.h" - -// Error value for find primitive -const TiXmlString::size_type TiXmlString::npos = static_cast(-1); - -// Null rep. -TiXmlString::Rep TiXmlString::nullrep_ = { 0, 0, { '\0' } }; - -void -TiXmlString::reserve(size_type cap) { - if (cap > capacity()) { - TiXmlString tmp; - tmp.init(length(), cap); - memcpy(tmp.start(), data(), length()); - swap(tmp); - } -} - -TiXmlString& -TiXmlString::assign(const char* str, size_type len) { - size_type cap = capacity(); - if (len > cap || cap > 3 * (len + 8)) { - TiXmlString tmp; - tmp.init(len); - memcpy(tmp.start(), str, len); - swap(tmp); - } else { - memmove(start(), str, len); - set_size(len); - } - return *this; -} - -TiXmlString& -TiXmlString::append(const char* str, size_type len) { - size_type newsize = length() + len; - if (newsize > capacity()) { reserve(newsize + capacity()); } - memmove(finish(), str, len); - set_size(newsize); - return *this; -} - -TiXmlString operator+(const TiXmlString& a, const TiXmlString& b) { - TiXmlString tmp; - tmp.reserve(a.length() + b.length()); - tmp += a; - tmp += b; - return tmp; -} - -TiXmlString operator+(const TiXmlString& a, const char* b) { - TiXmlString tmp; - TiXmlString::size_type b_len = static_cast(strlen(b)); - tmp.reserve(a.length() + b_len); - tmp += a; - tmp.append(b, b_len); - return tmp; -} - -TiXmlString operator+(const char* a, const TiXmlString& b) { - TiXmlString tmp; - TiXmlString::size_type a_len = static_cast(strlen(a)); - tmp.reserve(a_len + b.length()); - tmp.append(a, a_len); - tmp += b; - return tmp; -} - -#endif // TIXML_USE_STL diff --git a/cameradar_standalone/src/tinyxml.cpp b/cameradar_standalone/src/tinyxml.cpp deleted file mode 100644 index 5765564..0000000 --- a/cameradar_standalone/src/tinyxml.cpp +++ /dev/null @@ -1,1547 +0,0 @@ -/* -www.sourceforge.net/projects/tinyxml -Original code by Lee Thomason (www.grinninglizard.com) - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any -damages arising from the use of this software. - -Permission is granted to anyone to use this software for any -purpose, including commercial applications, and to alter it and -redistribute it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must -not claim that you wrote the original software. If you use this -software in a product, an acknowledgment in the product documentation -would be appreciated but is not required. - -2. Altered source versions must be plainly marked as such, and -must not be misrepresented as being the original software. - -3. This notice may not be removed or altered from any source -distribution. -*/ - -#include - -#ifdef TIXML_USE_STL -#include -#include -#endif - -#include "tinyxml.h" - -FILE* TiXmlFOpen(const char* filename, const char* mode); - -bool TiXmlBase::condenseWhiteSpace = true; - -// Microsoft compiler security -FILE* -TiXmlFOpen(const char* filename, const char* mode) { -#if defined(_MSC_VER) && (_MSC_VER >= 1400) - FILE* fp = 0; - errno_t err = fopen_s(&fp, filename, mode); - if (!err && fp) return fp; - return 0; -#else - return fopen(filename, mode); -#endif -} - -void -TiXmlBase::EncodeString(const TIXML_STRING& str, TIXML_STRING* outString) { - int i = 0; - - while (i < (int)str.length()) { - unsigned char c = (unsigned char)str[i]; - - if (c == '&' && i < ((int)str.length() - 2) && str[i + 1] == '#' && str[i + 2] == 'x') { - // Hexadecimal character reference. - // Pass through unchanged. - // © -- copyright symbol, for example. - // - // The -1 is a bug fix from Rob Laveaux. It keeps - // an overflow from happening if there is no ';'. - // There are actually 2 ways to exit this loop - - // while fails (error case) and break (semicolon found). - // However, there is no mechanism (currently) for - // this function to return an error. - while (i < (int)str.length() - 1) { - outString->append(str.c_str() + i, 1); - ++i; - if (str[i] == ';') break; - } - } else if (c == '&') { - outString->append(entity[0].str, entity[0].strLength); - ++i; - } else if (c == '<') { - outString->append(entity[1].str, entity[1].strLength); - ++i; - } else if (c == '>') { - outString->append(entity[2].str, entity[2].strLength); - ++i; - } else if (c == '\"') { - outString->append(entity[3].str, entity[3].strLength); - ++i; - } else if (c == '\'') { - outString->append(entity[4].str, entity[4].strLength); - ++i; - } else if (c < 32) { - // Easy pass at non-alpha/numeric/symbol - // Below 32 is symbolic. - char buf[32]; - -#if defined(TIXML_SNPRINTF) - TIXML_SNPRINTF(buf, sizeof(buf), "&#x%02X;", (unsigned)(c & 0xff)); -#else - sprintf(buf, "&#x%02X;", (unsigned)(c & 0xff)); -#endif - - //*ME: warning C4267: convert 'size_t' to 'int' - //*ME: Int-Cast to make compiler happy ... - outString->append(buf, (int)strlen(buf)); - ++i; - } else { - // char realc = (char) c; - // outString->append( &realc, 1 ); - *outString += (char)c; // somewhat more efficient function call. - ++i; - } - } -} - -TiXmlNode::TiXmlNode(NodeType _type) : TiXmlBase() { - parent = 0; - type = _type; - firstChild = 0; - lastChild = 0; - prev = 0; - next = 0; -} - -TiXmlNode::~TiXmlNode() { - TiXmlNode* node = firstChild; - TiXmlNode* temp = 0; - - while (node) { - temp = node; - node = node->next; - delete temp; - } -} - -void -TiXmlNode::CopyTo(TiXmlNode* target) const { - target->SetValue(value.c_str()); - target->userData = userData; - target->location = location; -} - -void -TiXmlNode::Clear() { - TiXmlNode* node = firstChild; - TiXmlNode* temp = 0; - - while (node) { - temp = node; - node = node->next; - delete temp; - } - - firstChild = 0; - lastChild = 0; -} - -TiXmlNode* -TiXmlNode::LinkEndChild(TiXmlNode* node) { - assert(node->parent == 0 || node->parent == this); - assert(node->GetDocument() == 0 || node->GetDocument() == this->GetDocument()); - - if (node->Type() == TiXmlNode::TINYXML_DOCUMENT) { - delete node; - if (GetDocument()) - GetDocument()->SetError(TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN); - return 0; - } - - node->parent = this; - - node->prev = lastChild; - node->next = 0; - - if (lastChild) - lastChild->next = node; - else - firstChild = node; // it was an empty list. - - lastChild = node; - return node; -} - -TiXmlNode* -TiXmlNode::InsertEndChild(const TiXmlNode& addThis) { - if (addThis.Type() == TiXmlNode::TINYXML_DOCUMENT) { - if (GetDocument()) - GetDocument()->SetError(TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN); - return 0; - } - TiXmlNode* node = addThis.Clone(); - if (!node) return 0; - - return LinkEndChild(node); -} - -TiXmlNode* -TiXmlNode::InsertBeforeChild(TiXmlNode* beforeThis, const TiXmlNode& addThis) { - if (!beforeThis || beforeThis->parent != this) { return 0; } - if (addThis.Type() == TiXmlNode::TINYXML_DOCUMENT) { - if (GetDocument()) - GetDocument()->SetError(TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN); - return 0; - } - - TiXmlNode* node = addThis.Clone(); - if (!node) return 0; - node->parent = this; - - node->next = beforeThis; - node->prev = beforeThis->prev; - if (beforeThis->prev) { - beforeThis->prev->next = node; - } else { - assert(firstChild == beforeThis); - firstChild = node; - } - beforeThis->prev = node; - return node; -} - -TiXmlNode* -TiXmlNode::InsertAfterChild(TiXmlNode* afterThis, const TiXmlNode& addThis) { - if (!afterThis || afterThis->parent != this) { return 0; } - if (addThis.Type() == TiXmlNode::TINYXML_DOCUMENT) { - if (GetDocument()) - GetDocument()->SetError(TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN); - return 0; - } - - TiXmlNode* node = addThis.Clone(); - if (!node) return 0; - node->parent = this; - - node->prev = afterThis; - node->next = afterThis->next; - if (afterThis->next) { - afterThis->next->prev = node; - } else { - assert(lastChild == afterThis); - lastChild = node; - } - afterThis->next = node; - return node; -} - -TiXmlNode* -TiXmlNode::ReplaceChild(TiXmlNode* replaceThis, const TiXmlNode& withThis) { - if (!replaceThis) return 0; - - if (replaceThis->parent != this) return 0; - - if (withThis.ToDocument()) { - // A document can never be a child. Thanks to Noam. - TiXmlDocument* document = GetDocument(); - if (document) - document->SetError(TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN); - return 0; - } - - TiXmlNode* node = withThis.Clone(); - if (!node) return 0; - - node->next = replaceThis->next; - node->prev = replaceThis->prev; - - if (replaceThis->next) - replaceThis->next->prev = node; - else - lastChild = node; - - if (replaceThis->prev) - replaceThis->prev->next = node; - else - firstChild = node; - - delete replaceThis; - node->parent = this; - return node; -} - -bool -TiXmlNode::RemoveChild(TiXmlNode* removeThis) { - if (!removeThis) { return false; } - - if (removeThis->parent != this) { - assert(0); - return false; - } - - if (removeThis->next) - removeThis->next->prev = removeThis->prev; - else - lastChild = removeThis->prev; - - if (removeThis->prev) - removeThis->prev->next = removeThis->next; - else - firstChild = removeThis->next; - - delete removeThis; - return true; -} - -const TiXmlNode* -TiXmlNode::FirstChild(const char* _value) const { - const TiXmlNode* node; - for (node = firstChild; node; node = node->next) { - if (strcmp(node->Value(), _value) == 0) return node; - } - return 0; -} - -const TiXmlNode* -TiXmlNode::LastChild(const char* _value) const { - const TiXmlNode* node; - for (node = lastChild; node; node = node->prev) { - if (strcmp(node->Value(), _value) == 0) return node; - } - return 0; -} - -const TiXmlNode* -TiXmlNode::IterateChildren(const TiXmlNode* previous) const { - if (!previous) { - return FirstChild(); - } else { - assert(previous->parent == this); - return previous->NextSibling(); - } -} - -const TiXmlNode* -TiXmlNode::IterateChildren(const char* val, const TiXmlNode* previous) const { - if (!previous) { - return FirstChild(val); - } else { - assert(previous->parent == this); - return previous->NextSibling(val); - } -} - -const TiXmlNode* -TiXmlNode::NextSibling(const char* _value) const { - const TiXmlNode* node; - for (node = next; node; node = node->next) { - if (strcmp(node->Value(), _value) == 0) return node; - } - return 0; -} - -const TiXmlNode* -TiXmlNode::PreviousSibling(const char* _value) const { - const TiXmlNode* node; - for (node = prev; node; node = node->prev) { - if (strcmp(node->Value(), _value) == 0) return node; - } - return 0; -} - -void -TiXmlElement::RemoveAttribute(const char* name) { -#ifdef TIXML_USE_STL - TIXML_STRING str(name); - TiXmlAttribute* node = attributeSet.Find(str); -#else - TiXmlAttribute* node = attributeSet.Find(name); -#endif - if (node) { - attributeSet.Remove(node); - delete node; - } -} - -const TiXmlElement* -TiXmlNode::FirstChildElement() const { - const TiXmlNode* node; - - for (node = FirstChild(); node; node = node->NextSibling()) { - if (node->ToElement()) return node->ToElement(); - } - return 0; -} - -const TiXmlElement* -TiXmlNode::FirstChildElement(const char* _value) const { - const TiXmlNode* node; - - for (node = FirstChild(_value); node; node = node->NextSibling(_value)) { - if (node->ToElement()) return node->ToElement(); - } - return 0; -} - -const TiXmlElement* -TiXmlNode::NextSiblingElement() const { - const TiXmlNode* node; - - for (node = NextSibling(); node; node = node->NextSibling()) { - if (node->ToElement()) return node->ToElement(); - } - return 0; -} - -const TiXmlElement* -TiXmlNode::NextSiblingElement(const char* _value) const { - const TiXmlNode* node; - - for (node = NextSibling(_value); node; node = node->NextSibling(_value)) { - if (node->ToElement()) return node->ToElement(); - } - return 0; -} - -const TiXmlDocument* -TiXmlNode::GetDocument() const { - const TiXmlNode* node; - - for (node = this; node; node = node->parent) { - if (node->ToDocument()) return node->ToDocument(); - } - return 0; -} - -TiXmlElement::TiXmlElement(const char* _value) : TiXmlNode(TiXmlNode::TINYXML_ELEMENT) { - firstChild = lastChild = 0; - value = _value; -} - -#ifdef TIXML_USE_STL -TiXmlElement::TiXmlElement(const std::string& _value) : TiXmlNode(TiXmlNode::TINYXML_ELEMENT) { - firstChild = lastChild = 0; - value = _value; -} -#endif - -TiXmlElement::TiXmlElement(const TiXmlElement& copy) : TiXmlNode(TiXmlNode::TINYXML_ELEMENT) { - firstChild = lastChild = 0; - copy.CopyTo(this); -} - -TiXmlElement& TiXmlElement::operator=(const TiXmlElement& base) { - ClearThis(); - base.CopyTo(this); - return *this; -} - -TiXmlElement::~TiXmlElement() { ClearThis(); } - -void -TiXmlElement::ClearThis() { - Clear(); - while (attributeSet.First()) { - TiXmlAttribute* node = attributeSet.First(); - attributeSet.Remove(node); - delete node; - } -} - -const char* -TiXmlElement::Attribute(const char* name) const { - const TiXmlAttribute* node = attributeSet.Find(name); - if (node) return node->Value(); - return 0; -} - -#ifdef TIXML_USE_STL -const std::string* -TiXmlElement::Attribute(const std::string& name) const { - const TiXmlAttribute* attrib = attributeSet.Find(name); - if (attrib) return &attrib->ValueStr(); - return 0; -} -#endif - -const char* -TiXmlElement::Attribute(const char* name, int* i) const { - const TiXmlAttribute* attrib = attributeSet.Find(name); - const char* result = 0; - - if (attrib) { - result = attrib->Value(); - if (i) { attrib->QueryIntValue(i); } - } - return result; -} - -#ifdef TIXML_USE_STL -const std::string* -TiXmlElement::Attribute(const std::string& name, int* i) const { - const TiXmlAttribute* attrib = attributeSet.Find(name); - const std::string* result = 0; - - if (attrib) { - result = &attrib->ValueStr(); - if (i) { attrib->QueryIntValue(i); } - } - return result; -} -#endif - -const char* -TiXmlElement::Attribute(const char* name, double* d) const { - const TiXmlAttribute* attrib = attributeSet.Find(name); - const char* result = 0; - - if (attrib) { - result = attrib->Value(); - if (d) { attrib->QueryDoubleValue(d); } - } - return result; -} - -#ifdef TIXML_USE_STL -const std::string* -TiXmlElement::Attribute(const std::string& name, double* d) const { - const TiXmlAttribute* attrib = attributeSet.Find(name); - const std::string* result = 0; - - if (attrib) { - result = &attrib->ValueStr(); - if (d) { attrib->QueryDoubleValue(d); } - } - return result; -} -#endif - -int -TiXmlElement::QueryIntAttribute(const char* name, int* ival) const { - const TiXmlAttribute* attrib = attributeSet.Find(name); - if (!attrib) return TIXML_NO_ATTRIBUTE; - return attrib->QueryIntValue(ival); -} - -int -TiXmlElement::QueryUnsignedAttribute(const char* name, unsigned* value) const { - const TiXmlAttribute* node = attributeSet.Find(name); - if (!node) return TIXML_NO_ATTRIBUTE; - - int ival = 0; - int result = node->QueryIntValue(&ival); - *value = (unsigned)ival; - return result; -} - -int -TiXmlElement::QueryBoolAttribute(const char* name, bool* bval) const { - const TiXmlAttribute* node = attributeSet.Find(name); - if (!node) return TIXML_NO_ATTRIBUTE; - - int result = TIXML_WRONG_TYPE; - if (StringEqual(node->Value(), "true", true, TIXML_ENCODING_UNKNOWN) || - StringEqual(node->Value(), "yes", true, TIXML_ENCODING_UNKNOWN) || - StringEqual(node->Value(), "1", true, TIXML_ENCODING_UNKNOWN)) { - *bval = true; - result = TIXML_SUCCESS; - } else if (StringEqual(node->Value(), "false", true, TIXML_ENCODING_UNKNOWN) || - StringEqual(node->Value(), "no", true, TIXML_ENCODING_UNKNOWN) || - StringEqual(node->Value(), "0", true, TIXML_ENCODING_UNKNOWN)) { - *bval = false; - result = TIXML_SUCCESS; - } - return result; -} - -#ifdef TIXML_USE_STL -int -TiXmlElement::QueryIntAttribute(const std::string& name, int* ival) const { - const TiXmlAttribute* attrib = attributeSet.Find(name); - if (!attrib) return TIXML_NO_ATTRIBUTE; - return attrib->QueryIntValue(ival); -} -#endif - -int -TiXmlElement::QueryDoubleAttribute(const char* name, double* dval) const { - const TiXmlAttribute* attrib = attributeSet.Find(name); - if (!attrib) return TIXML_NO_ATTRIBUTE; - return attrib->QueryDoubleValue(dval); -} - -#ifdef TIXML_USE_STL -int -TiXmlElement::QueryDoubleAttribute(const std::string& name, double* dval) const { - const TiXmlAttribute* attrib = attributeSet.Find(name); - if (!attrib) return TIXML_NO_ATTRIBUTE; - return attrib->QueryDoubleValue(dval); -} -#endif - -void -TiXmlElement::SetAttribute(const char* name, int val) { - TiXmlAttribute* attrib = attributeSet.FindOrCreate(name); - if (attrib) { attrib->SetIntValue(val); } -} - -#ifdef TIXML_USE_STL -void -TiXmlElement::SetAttribute(const std::string& name, int val) { - TiXmlAttribute* attrib = attributeSet.FindOrCreate(name); - if (attrib) { attrib->SetIntValue(val); } -} -#endif - -void -TiXmlElement::SetDoubleAttribute(const char* name, double val) { - TiXmlAttribute* attrib = attributeSet.FindOrCreate(name); - if (attrib) { attrib->SetDoubleValue(val); } -} - -#ifdef TIXML_USE_STL -void -TiXmlElement::SetDoubleAttribute(const std::string& name, double val) { - TiXmlAttribute* attrib = attributeSet.FindOrCreate(name); - if (attrib) { attrib->SetDoubleValue(val); } -} -#endif - -void -TiXmlElement::SetAttribute(const char* cname, const char* cvalue) { - TiXmlAttribute* attrib = attributeSet.FindOrCreate(cname); - if (attrib) { attrib->SetValue(cvalue); } -} - -#ifdef TIXML_USE_STL -void -TiXmlElement::SetAttribute(const std::string& _name, const std::string& _value) { - TiXmlAttribute* attrib = attributeSet.FindOrCreate(_name); - if (attrib) { attrib->SetValue(_value); } -} -#endif - -void -TiXmlElement::Print(FILE* cfile, int depth) const { - int i; - assert(cfile); - for (i = 0; i < depth; i++) { fprintf(cfile, " "); } - - fprintf(cfile, "<%s", value.c_str()); - - const TiXmlAttribute* attrib; - for (attrib = attributeSet.First(); attrib; attrib = attrib->Next()) { - fprintf(cfile, " "); - attrib->Print(cfile, depth); - } - - // There are 3 different formatting approaches: - // 1) An element without children is printed as a node - // 2) An element with only a text child is printed as text - // 3) An element with children is printed on multiple lines. - TiXmlNode* node; - if (!firstChild) { - fprintf(cfile, " />"); - } else if (firstChild == lastChild && firstChild->ToText()) { - fprintf(cfile, ">"); - firstChild->Print(cfile, depth + 1); - fprintf(cfile, "", value.c_str()); - } else { - fprintf(cfile, ">"); - - for (node = firstChild; node; node = node->NextSibling()) { - if (!node->ToText()) { fprintf(cfile, "\n"); } - node->Print(cfile, depth + 1); - } - fprintf(cfile, "\n"); - for (i = 0; i < depth; ++i) { fprintf(cfile, " "); } - fprintf(cfile, "", value.c_str()); - } -} - -void -TiXmlElement::CopyTo(TiXmlElement* target) const { - // superclass: - TiXmlNode::CopyTo(target); - - // Element class: - // Clone the attributes, then clone the children. - const TiXmlAttribute* attribute = 0; - for (attribute = attributeSet.First(); attribute; attribute = attribute->Next()) { - target->SetAttribute(attribute->Name(), attribute->Value()); - } - - TiXmlNode* node = 0; - for (node = firstChild; node; node = node->NextSibling()) { - target->LinkEndChild(node->Clone()); - } -} - -bool -TiXmlElement::Accept(TiXmlVisitor* visitor) const { - if (visitor->VisitEnter(*this, attributeSet.First())) { - for (const TiXmlNode* node = FirstChild(); node; node = node->NextSibling()) { - if (!node->Accept(visitor)) break; - } - } - return visitor->VisitExit(*this); -} - -TiXmlNode* -TiXmlElement::Clone() const { - TiXmlElement* clone = new TiXmlElement(Value()); - if (!clone) return 0; - - CopyTo(clone); - return clone; -} - -const char* -TiXmlElement::GetText() const { - const TiXmlNode* child = this->FirstChild(); - if (child) { - const TiXmlText* childText = child->ToText(); - if (childText) { return childText->Value(); } - } - return 0; -} - -TiXmlDocument::TiXmlDocument() : TiXmlNode(TiXmlNode::TINYXML_DOCUMENT) { - tabsize = 4; - useMicrosoftBOM = false; - ClearError(); -} - -TiXmlDocument::TiXmlDocument(const char* documentName) : TiXmlNode(TiXmlNode::TINYXML_DOCUMENT) { - tabsize = 4; - useMicrosoftBOM = false; - value = documentName; - ClearError(); -} - -#ifdef TIXML_USE_STL -TiXmlDocument::TiXmlDocument(const std::string& documentName) -: TiXmlNode(TiXmlNode::TINYXML_DOCUMENT) { - tabsize = 4; - useMicrosoftBOM = false; - value = documentName; - ClearError(); -} -#endif - -TiXmlDocument::TiXmlDocument(const TiXmlDocument& copy) : TiXmlNode(TiXmlNode::TINYXML_DOCUMENT) { - copy.CopyTo(this); -} - -TiXmlDocument& TiXmlDocument::operator=(const TiXmlDocument& copy) { - Clear(); - copy.CopyTo(this); - return *this; -} - -bool -TiXmlDocument::LoadFile(TiXmlEncoding encoding) { - return LoadFile(Value(), encoding); -} - -bool -TiXmlDocument::SaveFile() const { - return SaveFile(Value()); -} - -bool -TiXmlDocument::LoadFile(const char* _filename, TiXmlEncoding encoding) { - TIXML_STRING filename(_filename); - value = filename; - - // reading in binary mode so that tinyxml can normalize the EOL - FILE* file = TiXmlFOpen(value.c_str(), "rb"); - - if (file) { - bool result = LoadFile(file, encoding); - fclose(file); - return result; - } else { - SetError(TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN); - return false; - } -} - -bool -TiXmlDocument::LoadFile(FILE* file, TiXmlEncoding encoding) { - if (!file) { - SetError(TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN); - return false; - } - - // Delete the existing data: - Clear(); - location.Clear(); - - // Get the file size, so we can pre-allocate the string. HUGE speed impact. - long length = 0; - fseek(file, 0, SEEK_END); - length = ftell(file); - fseek(file, 0, SEEK_SET); - - // Strange case, but good to handle up front. - if (length <= 0) { - SetError(TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN); - return false; - } - - // Subtle bug here. TinyXml did use fgets. But from the XML spec: - // 2.11 End-of-Line Handling - // - // - // ...the XML processor MUST behave as if it normalized all line breaks in external - // parsed entities (including the document entity) on input, before parsing, by translating - // both the two-character sequence #xD #xA and any #xD that is not followed by #xA to - // a single #xA character. - // - // - // It is not clear fgets does that, and certainly isn't clear it works cross platform. - // Generally, you expect fgets to translate from the convention of the OS to the c/unix - // convention, and not work generally. - - /* - while( fgets( buf, sizeof(buf), file ) ) - { - data += buf; - } - */ - - char* buf = new char[length + 1]; - buf[0] = 0; - - if (fread(buf, length, 1, file) != 1) { - delete[] buf; - SetError(TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN); - return false; - } - - // Process the buffer in place to normalize new lines. (See comment above.) - // Copies from the 'p' to 'q' pointer, where p can advance faster if - // a newline-carriage return is hit. - // - // Wikipedia: - // Systems based on ASCII or a compatible character set use either LF (Line feed, '\n', 0x0A, - // 10 in decimal) or - // CR (Carriage return, '\r', 0x0D, 13 in decimal) individually, or CR followed by LF (CR+LF, - // 0x0D 0x0A)... - // * LF: Multics, Unix and Unix-like systems (GNU/Linux, AIX, Xenix, Mac OS X, FreeBSD, - //etc.), BeOS, Amiga, RISC OS, and others - // * CR+LF: DEC RT-11 and most other early non-Unix, non-IBM OSes, CP/M, MP/M, DOS, OS/2, - //Microsoft Windows, Symbian OS - // * CR: Commodore 8-bit machines, Apple II family, Mac OS up to version 9 and OS-9 - - const char* p = buf; // the read head - char* q = buf; // the write head - const char CR = 0x0d; - const char LF = 0x0a; - - buf[length] = 0; - while (*p) { - assert(p < (buf + length)); - assert(q <= (buf + length)); - assert(q <= p); - - if (*p == CR) { - *q++ = LF; - p++; - if (*p == LF) { // check for CR+LF (and skip LF) - p++; - } - } else { - *q++ = *p++; - } - } - assert(q <= (buf + length)); - *q = 0; - - Parse(buf, 0, encoding); - - delete[] buf; - return !Error(); -} - -bool -TiXmlDocument::SaveFile(const char* filename) const { - // The old c stuff lives on... - FILE* fp = TiXmlFOpen(filename, "w"); - if (fp) { - bool result = SaveFile(fp); - fclose(fp); - return result; - } - return false; -} - -bool -TiXmlDocument::SaveFile(FILE* fp) const { - if (useMicrosoftBOM) { - const unsigned char TIXML_UTF_LEAD_0 = 0xefU; - const unsigned char TIXML_UTF_LEAD_1 = 0xbbU; - const unsigned char TIXML_UTF_LEAD_2 = 0xbfU; - - fputc(TIXML_UTF_LEAD_0, fp); - fputc(TIXML_UTF_LEAD_1, fp); - fputc(TIXML_UTF_LEAD_2, fp); - } - Print(fp, 0); - return (ferror(fp) == 0); -} - -void -TiXmlDocument::CopyTo(TiXmlDocument* target) const { - TiXmlNode::CopyTo(target); - - target->error = error; - target->errorId = errorId; - target->errorDesc = errorDesc; - target->tabsize = tabsize; - target->errorLocation = errorLocation; - target->useMicrosoftBOM = useMicrosoftBOM; - - TiXmlNode* node = 0; - for (node = firstChild; node; node = node->NextSibling()) { - target->LinkEndChild(node->Clone()); - } -} - -TiXmlNode* -TiXmlDocument::Clone() const { - TiXmlDocument* clone = new TiXmlDocument(); - if (!clone) return 0; - - CopyTo(clone); - return clone; -} - -void -TiXmlDocument::Print(FILE* cfile, int depth) const { - assert(cfile); - for (const TiXmlNode* node = FirstChild(); node; node = node->NextSibling()) { - node->Print(cfile, depth); - fprintf(cfile, "\n"); - } -} - -bool -TiXmlDocument::Accept(TiXmlVisitor* visitor) const { - if (visitor->VisitEnter(*this)) { - for (const TiXmlNode* node = FirstChild(); node; node = node->NextSibling()) { - if (!node->Accept(visitor)) break; - } - } - return visitor->VisitExit(*this); -} - -const TiXmlAttribute* -TiXmlAttribute::Next() const { - // We are using knowledge of the sentinel. The sentinel - // have a value or name. - if (next->value.empty() && next->name.empty()) return 0; - return next; -} - -/* -TiXmlAttribute* TiXmlAttribute::Next() -{ - // We are using knowledge of the sentinel. The sentinel - // have a value or name. - if ( next->value.empty() && next->name.empty() ) - return 0; - return next; -} -*/ - -const TiXmlAttribute* -TiXmlAttribute::Previous() const { - // We are using knowledge of the sentinel. The sentinel - // have a value or name. - if (prev->value.empty() && prev->name.empty()) return 0; - return prev; -} - -/* -TiXmlAttribute* TiXmlAttribute::Previous() -{ - // We are using knowledge of the sentinel. The sentinel - // have a value or name. - if ( prev->value.empty() && prev->name.empty() ) - return 0; - return prev; -} -*/ - -void -TiXmlAttribute::Print(FILE* cfile, int /*depth*/, TIXML_STRING* str) const { - TIXML_STRING n, v; - - EncodeString(name, &n); - EncodeString(value, &v); - - if (value.find('\"') == TIXML_STRING::npos) { - if (cfile) { fprintf(cfile, "%s=\"%s\"", n.c_str(), v.c_str()); } - if (str) { - (*str) += n; - (*str) += "=\""; - (*str) += v; - (*str) += "\""; - } - } else { - if (cfile) { fprintf(cfile, "%s='%s'", n.c_str(), v.c_str()); } - if (str) { - (*str) += n; - (*str) += "='"; - (*str) += v; - (*str) += "'"; - } - } -} - -int -TiXmlAttribute::QueryIntValue(int* ival) const { - if (TIXML_SSCANF(value.c_str(), "%d", ival) == 1) return TIXML_SUCCESS; - return TIXML_WRONG_TYPE; -} - -int -TiXmlAttribute::QueryDoubleValue(double* dval) const { - if (TIXML_SSCANF(value.c_str(), "%lf", dval) == 1) return TIXML_SUCCESS; - return TIXML_WRONG_TYPE; -} - -void -TiXmlAttribute::SetIntValue(int _value) { - char buf[64]; -#if defined(TIXML_SNPRINTF) - TIXML_SNPRINTF(buf, sizeof(buf), "%d", _value); -#else - sprintf(buf, "%d", _value); -#endif - SetValue(buf); -} - -void -TiXmlAttribute::SetDoubleValue(double _value) { - char buf[256]; -#if defined(TIXML_SNPRINTF) - TIXML_SNPRINTF(buf, sizeof(buf), "%g", _value); -#else - sprintf(buf, "%g", _value); -#endif - SetValue(buf); -} - -int -TiXmlAttribute::IntValue() const { - return atoi(value.c_str()); -} - -double -TiXmlAttribute::DoubleValue() const { - return atof(value.c_str()); -} - -TiXmlComment::TiXmlComment(const TiXmlComment& copy) : TiXmlNode(TiXmlNode::TINYXML_COMMENT) { - copy.CopyTo(this); -} - -TiXmlComment& TiXmlComment::operator=(const TiXmlComment& base) { - Clear(); - base.CopyTo(this); - return *this; -} - -void -TiXmlComment::Print(FILE* cfile, int depth) const { - assert(cfile); - for (int i = 0; i < depth; i++) { fprintf(cfile, " "); } - fprintf(cfile, "", value.c_str()); -} - -void -TiXmlComment::CopyTo(TiXmlComment* target) const { - TiXmlNode::CopyTo(target); -} - -bool -TiXmlComment::Accept(TiXmlVisitor* visitor) const { - return visitor->Visit(*this); -} - -TiXmlNode* -TiXmlComment::Clone() const { - TiXmlComment* clone = new TiXmlComment(); - - if (!clone) return 0; - - CopyTo(clone); - return clone; -} - -void -TiXmlText::Print(FILE* cfile, int depth) const { - assert(cfile); - if (cdata) { - int i; - fprintf(cfile, "\n"); - for (i = 0; i < depth; i++) { fprintf(cfile, " "); } - fprintf(cfile, "\n", value.c_str()); // unformatted output - } else { - TIXML_STRING buffer; - EncodeString(value, &buffer); - fprintf(cfile, "%s", buffer.c_str()); - } -} - -void -TiXmlText::CopyTo(TiXmlText* target) const { - TiXmlNode::CopyTo(target); - target->cdata = cdata; -} - -bool -TiXmlText::Accept(TiXmlVisitor* visitor) const { - return visitor->Visit(*this); -} - -TiXmlNode* -TiXmlText::Clone() const { - TiXmlText* clone = 0; - clone = new TiXmlText(""); - - if (!clone) return 0; - - CopyTo(clone); - return clone; -} - -TiXmlDeclaration::TiXmlDeclaration(const char* _version, - const char* _encoding, - const char* _standalone) -: TiXmlNode(TiXmlNode::TINYXML_DECLARATION) { - version = _version; - encoding = _encoding; - standalone = _standalone; -} - -#ifdef TIXML_USE_STL -TiXmlDeclaration::TiXmlDeclaration(const std::string& _version, - const std::string& _encoding, - const std::string& _standalone) -: TiXmlNode(TiXmlNode::TINYXML_DECLARATION) { - version = _version; - encoding = _encoding; - standalone = _standalone; -} -#endif - -TiXmlDeclaration::TiXmlDeclaration(const TiXmlDeclaration& copy) -: TiXmlNode(TiXmlNode::TINYXML_DECLARATION) { - copy.CopyTo(this); -} - -TiXmlDeclaration& TiXmlDeclaration::operator=(const TiXmlDeclaration& copy) { - Clear(); - copy.CopyTo(this); - return *this; -} - -void -TiXmlDeclaration::Print(FILE* cfile, int /*depth*/, TIXML_STRING* str) const { - if (cfile) fprintf(cfile, ""); - if (str) (*str) += "?>"; -} - -void -TiXmlDeclaration::CopyTo(TiXmlDeclaration* target) const { - TiXmlNode::CopyTo(target); - - target->version = version; - target->encoding = encoding; - target->standalone = standalone; -} - -bool -TiXmlDeclaration::Accept(TiXmlVisitor* visitor) const { - return visitor->Visit(*this); -} - -TiXmlNode* -TiXmlDeclaration::Clone() const { - TiXmlDeclaration* clone = new TiXmlDeclaration(); - - if (!clone) return 0; - - CopyTo(clone); - return clone; -} - -void -TiXmlUnknown::Print(FILE* cfile, int depth) const { - for (int i = 0; i < depth; i++) fprintf(cfile, " "); - fprintf(cfile, "<%s>", value.c_str()); -} - -void -TiXmlUnknown::CopyTo(TiXmlUnknown* target) const { - TiXmlNode::CopyTo(target); -} - -bool -TiXmlUnknown::Accept(TiXmlVisitor* visitor) const { - return visitor->Visit(*this); -} - -TiXmlNode* -TiXmlUnknown::Clone() const { - TiXmlUnknown* clone = new TiXmlUnknown(); - - if (!clone) return 0; - - CopyTo(clone); - return clone; -} - -TiXmlAttributeSet::TiXmlAttributeSet() { - sentinel.next = &sentinel; - sentinel.prev = &sentinel; -} - -TiXmlAttributeSet::~TiXmlAttributeSet() { - assert(sentinel.next == &sentinel); - assert(sentinel.prev == &sentinel); -} - -void -TiXmlAttributeSet::Add(TiXmlAttribute* addMe) { -#ifdef TIXML_USE_STL - assert(!Find(TIXML_STRING(addMe->Name()))); // Shouldn't be multiply adding to the set. -#else - assert(!Find(addMe->Name())); // Shouldn't be multiply adding to the set. -#endif - - addMe->next = &sentinel; - addMe->prev = sentinel.prev; - - sentinel.prev->next = addMe; - sentinel.prev = addMe; -} - -void -TiXmlAttributeSet::Remove(TiXmlAttribute* removeMe) { - TiXmlAttribute* node; - - for (node = sentinel.next; node != &sentinel; node = node->next) { - if (node == removeMe) { - node->prev->next = node->next; - node->next->prev = node->prev; - node->next = 0; - node->prev = 0; - return; - } - } - assert(0); // we tried to remove a non-linked attribute. -} - -#ifdef TIXML_USE_STL -TiXmlAttribute* -TiXmlAttributeSet::Find(const std::string& name) const { - for (TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next) { - if (node->name == name) return node; - } - return 0; -} - -TiXmlAttribute* -TiXmlAttributeSet::FindOrCreate(const std::string& _name) { - TiXmlAttribute* attrib = Find(_name); - if (!attrib) { - attrib = new TiXmlAttribute(); - Add(attrib); - attrib->SetName(_name); - } - return attrib; -} -#endif - -TiXmlAttribute* -TiXmlAttributeSet::Find(const char* name) const { - for (TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next) { - if (strcmp(node->name.c_str(), name) == 0) return node; - } - return 0; -} - -TiXmlAttribute* -TiXmlAttributeSet::FindOrCreate(const char* _name) { - TiXmlAttribute* attrib = Find(_name); - if (!attrib) { - attrib = new TiXmlAttribute(); - Add(attrib); - attrib->SetName(_name); - } - return attrib; -} - -#ifdef TIXML_USE_STL -std::istream& operator>>(std::istream& in, TiXmlNode& base) { - TIXML_STRING tag; - tag.reserve(8 * 1000); - base.StreamIn(&in, &tag); - - base.Parse(tag.c_str(), 0, TIXML_DEFAULT_ENCODING); - return in; -} -#endif - -#ifdef TIXML_USE_STL -std::ostream& operator<<(std::ostream& out, const TiXmlNode& base) { - TiXmlPrinter printer; - printer.SetStreamPrinting(); - base.Accept(&printer); - out << printer.Str(); - - return out; -} - -std::string& operator<<(std::string& out, const TiXmlNode& base) { - TiXmlPrinter printer; - printer.SetStreamPrinting(); - base.Accept(&printer); - out.append(printer.Str()); - - return out; -} -#endif - -TiXmlHandle -TiXmlHandle::FirstChild() const { - if (node) { - TiXmlNode* child = node->FirstChild(); - if (child) return TiXmlHandle(child); - } - return TiXmlHandle(0); -} - -TiXmlHandle -TiXmlHandle::FirstChild(const char* value) const { - if (node) { - TiXmlNode* child = node->FirstChild(value); - if (child) return TiXmlHandle(child); - } - return TiXmlHandle(0); -} - -TiXmlHandle -TiXmlHandle::FirstChildElement() const { - if (node) { - TiXmlElement* child = node->FirstChildElement(); - if (child) return TiXmlHandle(child); - } - return TiXmlHandle(0); -} - -TiXmlHandle -TiXmlHandle::FirstChildElement(const char* value) const { - if (node) { - TiXmlElement* child = node->FirstChildElement(value); - if (child) return TiXmlHandle(child); - } - return TiXmlHandle(0); -} - -TiXmlHandle -TiXmlHandle::Child(int count) const { - if (node) { - int i; - TiXmlNode* child = node->FirstChild(); - for (i = 0; child && i < count; child = child->NextSibling(), ++i) { - // nothing - } - if (child) return TiXmlHandle(child); - } - return TiXmlHandle(0); -} - -TiXmlHandle -TiXmlHandle::Child(const char* value, int count) const { - if (node) { - int i; - TiXmlNode* child = node->FirstChild(value); - for (i = 0; child && i < count; child = child->NextSibling(value), ++i) { - // nothing - } - if (child) return TiXmlHandle(child); - } - return TiXmlHandle(0); -} - -TiXmlHandle -TiXmlHandle::ChildElement(int count) const { - if (node) { - int i; - TiXmlElement* child = node->FirstChildElement(); - for (i = 0; child && i < count; child = child->NextSiblingElement(), ++i) { - // nothing - } - if (child) return TiXmlHandle(child); - } - return TiXmlHandle(0); -} - -TiXmlHandle -TiXmlHandle::ChildElement(const char* value, int count) const { - if (node) { - int i; - TiXmlElement* child = node->FirstChildElement(value); - for (i = 0; child && i < count; child = child->NextSiblingElement(value), ++i) { - // nothing - } - if (child) return TiXmlHandle(child); - } - return TiXmlHandle(0); -} - -bool -TiXmlPrinter::VisitEnter(const TiXmlDocument&) { - return true; -} - -bool -TiXmlPrinter::VisitExit(const TiXmlDocument&) { - return true; -} - -bool -TiXmlPrinter::VisitEnter(const TiXmlElement& element, const TiXmlAttribute* firstAttribute) { - DoIndent(); - buffer += "<"; - buffer += element.Value(); - - for (const TiXmlAttribute* attrib = firstAttribute; attrib; attrib = attrib->Next()) { - buffer += " "; - attrib->Print(0, 0, &buffer); - } - - if (!element.FirstChild()) { - buffer += " />"; - DoLineBreak(); - } else { - buffer += ">"; - if (element.FirstChild()->ToText() && element.LastChild() == element.FirstChild() && - element.FirstChild()->ToText()->CDATA() == false) { - simpleTextPrint = true; - // no DoLineBreak()! - } else { - DoLineBreak(); - } - } - ++depth; - return true; -} - -bool -TiXmlPrinter::VisitExit(const TiXmlElement& element) { - --depth; - if (!element.FirstChild()) { - // nothing. - } else { - if (simpleTextPrint) { - simpleTextPrint = false; - } else { - DoIndent(); - } - buffer += ""; - DoLineBreak(); - } - return true; -} - -bool -TiXmlPrinter::Visit(const TiXmlText& text) { - if (text.CDATA()) { - DoIndent(); - buffer += ""; - DoLineBreak(); - } else if (simpleTextPrint) { - TIXML_STRING str; - TiXmlBase::EncodeString(text.ValueTStr(), &str); - buffer += str; - } else { - DoIndent(); - TIXML_STRING str; - TiXmlBase::EncodeString(text.ValueTStr(), &str); - buffer += str; - DoLineBreak(); - } - return true; -} - -bool -TiXmlPrinter::Visit(const TiXmlDeclaration& declaration) { - DoIndent(); - declaration.Print(0, 0, &buffer); - DoLineBreak(); - return true; -} - -bool -TiXmlPrinter::Visit(const TiXmlComment& comment) { - DoIndent(); - buffer += ""; - DoLineBreak(); - return true; -} - -bool -TiXmlPrinter::Visit(const TiXmlUnknown& unknown) { - DoIndent(); - buffer += "<"; - buffer += unknown.Value(); - buffer += ">"; - DoLineBreak(); - return true; -} diff --git a/cameradar_standalone/src/tinyxmlerror.cpp b/cameradar_standalone/src/tinyxmlerror.cpp deleted file mode 100644 index 568628c..0000000 --- a/cameradar_standalone/src/tinyxmlerror.cpp +++ /dev/null @@ -1,51 +0,0 @@ -/* -www.sourceforge.net/projects/tinyxml -Original code (2.0 and earlier )copyright (c) 2000-2006 Lee Thomason (www.grinninglizard.com) - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any -damages arising from the use of this software. - -Permission is granted to anyone to use this software for any -purpose, including commercial applications, and to alter it and -redistribute it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must -not claim that you wrote the original software. If you use this -software in a product, an acknowledgment in the product documentation -would be appreciated but is not required. - -2. Altered source versions must be plainly marked as such, and -must not be misrepresented as being the original software. - -3. This notice may not be removed or altered from any source -distribution. -*/ - -#include "tinyxml.h" - -// The goal of the seperate error file is to make the first -// step towards localization. tinyxml (currently) only supports -// english error messages, but the could now be translated. -// -// It also cleans up the code a bit. -// - -const char* TiXmlBase::errorString[TiXmlBase::TIXML_ERROR_STRING_COUNT] = { - "No error", - "Error", - "Failed to open file", - "Error parsing Element.", - "Failed to read Element name", - "Error reading Element value.", - "Error reading Attributes.", - "Error: empty tag.", - "Error reading end tag.", - "Error parsing Unknown.", - "Error parsing Comment.", - "Error parsing Declaration.", - "Error document empty.", - "Error null (0) or unexpected EOF found in input stream.", - "Error parsing CDATA.", - "Error when TiXmlDocument added to document, because TiXmlDocument can only be at the root.", -}; diff --git a/cameradar_standalone/src/tinyxmlparser.cpp b/cameradar_standalone/src/tinyxmlparser.cpp deleted file mode 100644 index 000d5ce..0000000 --- a/cameradar_standalone/src/tinyxmlparser.cpp +++ /dev/null @@ -1,1409 +0,0 @@ -/* -www.sourceforge.net/projects/tinyxml -Original code by Lee Thomason (www.grinninglizard.com) - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any -damages arising from the use of this software. - -Permission is granted to anyone to use this software for any -purpose, including commercial applications, and to alter it and -redistribute it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must -not claim that you wrote the original software. If you use this -software in a product, an acknowledgment in the product documentation -would be appreciated but is not required. - -2. Altered source versions must be plainly marked as such, and -must not be misrepresented as being the original software. - -3. This notice may not be removed or altered from any source -distribution. -*/ - -#include -#include - -#include "tinyxml.h" - -//#define DEBUG_PARSER -#if defined(DEBUG_PARSER) -#if defined(DEBUG) && defined(_MSC_VER) -#include -#define TIXML_LOG OutputDebugString -#else -#define TIXML_LOG printf -#endif -#endif - -// Note tha "PutString" hardcodes the same list. This -// is less flexible than it appears. Changing the entries -// or order will break putstring. -TiXmlBase::Entity TiXmlBase::entity[TiXmlBase::NUM_ENTITY] = { { "&", 5, '&' }, - { "<", 4, '<' }, - { ">", 4, '>' }, - { """, 6, '\"' }, - { "'", 6, '\'' } }; - -// Bunch of unicode info at: -// http://www.unicode.org/faq/utf_bom.html -// Including the basic of this table, which determines the #bytes in the -// sequence from the lead byte. 1 placed for invalid sequences -- -// although the result will be junk, pass it through as much as possible. -// Beware of the non-characters in UTF-8: -// ef bb bf (Microsoft "lead bytes") -// ef bf be -// ef bf bf - -const unsigned char TIXML_UTF_LEAD_0 = 0xefU; -const unsigned char TIXML_UTF_LEAD_1 = 0xbbU; -const unsigned char TIXML_UTF_LEAD_2 = 0xbfU; - -const int TiXmlBase::utf8ByteTable[256] = - { - // 0 1 2 3 4 5 6 7 8 9 - //a b c d e f - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, // 0x00 - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, // 0x10 - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, // 0x20 - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, // 0x30 - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, // 0x40 - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, // 0x50 - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, // 0x60 - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, // 0x70 End of ASCII range - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, // 0x80 0x80 to 0xc1 invalid - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, // 0x90 - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, // 0xa0 - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, // 0xb0 - 1, 1, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, // 0xc0 0xc2 to 0xdf 2 byte - 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, // 0xd0 - 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, // 0xe0 0xe0 to 0xef 3 byte - 4, 4, 4, 4, 4, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1 // 0xf0 0xf0 to 0xf4 4 byte, 0xf5 and higher invalid - }; - -void -TiXmlBase::ConvertUTF32ToUTF8(unsigned long input, char* output, int* length) { - const unsigned long BYTE_MASK = 0xBF; - const unsigned long BYTE_MARK = 0x80; - const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; - - if (input < 0x80) - *length = 1; - else if (input < 0x800) - *length = 2; - else if (input < 0x10000) - *length = 3; - else if (input < 0x200000) - *length = 4; - else { - *length = 0; - return; - } // This code won't covert this correctly anyway. - - output += *length; - - // Scary scary fall throughs. - switch (*length) { - case 4: - --output; - *output = (char)((input | BYTE_MARK) & BYTE_MASK); - input >>= 6; - case 3: - --output; - *output = (char)((input | BYTE_MARK) & BYTE_MASK); - input >>= 6; - case 2: - --output; - *output = (char)((input | BYTE_MARK) & BYTE_MASK); - input >>= 6; - case 1: --output; *output = (char)(input | FIRST_BYTE_MARK[*length]); - } -} - -/*static*/ int -TiXmlBase::IsAlpha(unsigned char anyByte, TiXmlEncoding /*encoding*/) { - // This will only work for low-ascii, everything else is assumed to be a valid - // letter. I'm not sure this is the best approach, but it is quite tricky trying - // to figure out alhabetical vs. not across encoding. So take a very - // conservative approach. - - // if ( encoding == TIXML_ENCODING_UTF8 ) - // { - if (anyByte < 127) - return isalpha(anyByte); - else - return 1; // What else to do? The unicode set is huge...get the english ones right. - // } - // else - // { - // return isalpha( anyByte ); - // } -} - -/*static*/ int -TiXmlBase::IsAlphaNum(unsigned char anyByte, TiXmlEncoding /*encoding*/) { - // This will only work for low-ascii, everything else is assumed to be a valid - // letter. I'm not sure this is the best approach, but it is quite tricky trying - // to figure out alhabetical vs. not across encoding. So take a very - // conservative approach. - - // if ( encoding == TIXML_ENCODING_UTF8 ) - // { - if (anyByte < 127) - return isalnum(anyByte); - else - return 1; // What else to do? The unicode set is huge...get the english ones right. - // } - // else - // { - // return isalnum( anyByte ); - // } -} - -class TiXmlParsingData { - friend class TiXmlDocument; - -public: - void Stamp(const char* now, TiXmlEncoding encoding); - - const TiXmlCursor& - Cursor() const { - return cursor; - } - -private: - // Only used by the document! - TiXmlParsingData(const char* start, int _tabsize, int row, int col) { - assert(start); - stamp = start; - tabsize = _tabsize; - cursor.row = row; - cursor.col = col; - } - - TiXmlCursor cursor; - const char* stamp; - int tabsize; -}; - -void -TiXmlParsingData::Stamp(const char* now, TiXmlEncoding encoding) { - assert(now); - - // Do nothing if the tabsize is 0. - if (tabsize < 1) { return; } - - // Get the current row, column. - int row = cursor.row; - int col = cursor.col; - const char* p = stamp; - assert(p); - - while (p < now) { - // Treat p as unsigned, so we have a happy compiler. - const unsigned char* pU = (const unsigned char*)p; - - // Code contributed by Fletcher Dunn: (modified by lee) - switch (*pU) { - case 0: - // We *should* never get here, but in case we do, don't - // advance past the terminating null character, ever - return; - - case '\r': - // bump down to the next line - ++row; - col = 0; - // Eat the character - ++p; - - // Check for \r\n sequence, and treat this as a single character - if (*p == '\n') { ++p; } - break; - - case '\n': - // bump down to the next line - ++row; - col = 0; - - // Eat the character - ++p; - - // Check for \n\r sequence, and treat this as a single - // character. (Yes, this bizarre thing does occur still - // on some arcane platforms...) - if (*p == '\r') { ++p; } - break; - - case '\t': - // Eat the character - ++p; - - // Skip to next tab stop - col = (col / tabsize + 1) * tabsize; - break; - - case TIXML_UTF_LEAD_0: - if (encoding == TIXML_ENCODING_UTF8) { - if (*(p + 1) && *(p + 2)) { - // In these cases, don't advance the column. These are - // 0-width spaces. - if (*(pU + 1) == TIXML_UTF_LEAD_1 && *(pU + 2) == TIXML_UTF_LEAD_2) - p += 3; - else if (*(pU + 1) == 0xbfU && *(pU + 2) == 0xbeU) - p += 3; - else if (*(pU + 1) == 0xbfU && *(pU + 2) == 0xbfU) - p += 3; - else { - p += 3; - ++col; - } // A normal character. - } - } else { - ++p; - ++col; - } - break; - - default: - if (encoding == TIXML_ENCODING_UTF8) { - // Eat the 1 to 4 byte utf8 character. - int step = TiXmlBase::utf8ByteTable[*((const unsigned char*)p)]; - if (step == 0) step = 1; // Error case from bad encoding, but handle gracefully. - p += step; - - // Just advance one column, of course. - ++col; - } else { - ++p; - ++col; - } - break; - } - } - cursor.row = row; - cursor.col = col; - assert(cursor.row >= -1); - assert(cursor.col >= -1); - stamp = p; - assert(stamp); -} - -const char* -TiXmlBase::SkipWhiteSpace(const char* p, TiXmlEncoding encoding) { - if (!p || !*p) { return 0; } - if (encoding == TIXML_ENCODING_UTF8) { - while (*p) { - const unsigned char* pU = (const unsigned char*)p; - - // Skip the stupid Microsoft UTF-8 Byte order marks - if (*(pU + 0) == TIXML_UTF_LEAD_0 && *(pU + 1) == TIXML_UTF_LEAD_1 && - *(pU + 2) == TIXML_UTF_LEAD_2) { - p += 3; - continue; - } else if (*(pU + 0) == TIXML_UTF_LEAD_0 && *(pU + 1) == 0xbfU && *(pU + 2) == 0xbeU) { - p += 3; - continue; - } else if (*(pU + 0) == TIXML_UTF_LEAD_0 && *(pU + 1) == 0xbfU && *(pU + 2) == 0xbfU) { - p += 3; - continue; - } - - if (IsWhiteSpace(*p)) // Still using old rules for white space. - ++p; - else - break; - } - } else { - while (*p && IsWhiteSpace(*p)) ++p; - } - - return p; -} - -#ifdef TIXML_USE_STL -/*static*/ bool -TiXmlBase::StreamWhiteSpace(std::istream* in, TIXML_STRING* tag) { - for (;;) { - if (!in->good()) return false; - - int c = in->peek(); - // At this scope, we can't get to a document. So fail silently. - if (!IsWhiteSpace(c) || c <= 0) return true; - - *tag += (char)in->get(); - } -} - -/*static*/ bool -TiXmlBase::StreamTo(std::istream* in, int character, TIXML_STRING* tag) { - // assert( character > 0 && character < 128 ); // else it won't work in utf-8 - while (in->good()) { - int c = in->peek(); - if (c == character) return true; - if (c <= 0) // Silent failure: can't get document at this scope - return false; - - in->get(); - *tag += (char)c; - } - return false; -} -#endif - -// One of TinyXML's more performance demanding functions. Try to keep the memory overhead down. The -// "assign" optimization removes over 10% of the execution time. -// -const char* -TiXmlBase::ReadName(const char* p, TIXML_STRING* name, TiXmlEncoding encoding) { - // Oddly, not supported on some comilers, - // name->clear(); - // So use this: - *name = ""; - assert(p); - - // Names start with letters or underscores. - // Of course, in unicode, tinyxml has no idea what a letter *is*. The - // algorithm is generous. - // - // After that, they can be letters, underscores, numbers, - // hyphens, or colons. (Colons are valid ony for namespaces, - // but tinyxml can't tell namespaces from names.) - if (p && *p && (IsAlpha((unsigned char)*p, encoding) || *p == '_')) { - const char* start = p; - while (p && *p && (IsAlphaNum((unsigned char)*p, encoding) || *p == '_' || *p == '-' || - *p == '.' || *p == ':')) { - //(*name) += *p; // expensive - ++p; - } - if (p - start > 0) { name->assign(start, p - start); } - return p; - } - return 0; -} - -const char* -TiXmlBase::GetEntity(const char* p, char* value, int* length, TiXmlEncoding encoding) { - // Presume an entity, and pull it out. - TIXML_STRING ent; - int i; - *length = 0; - - if (*(p + 1) && *(p + 1) == '#' && *(p + 2)) { - unsigned long ucs = 0; - ptrdiff_t delta = 0; - unsigned mult = 1; - - if (*(p + 2) == 'x') { - // Hexadecimal. - if (!*(p + 3)) return 0; - - const char* q = p + 3; - q = strchr(q, ';'); - - if (!q || !*q) return 0; - - delta = q - p; - --q; - - while (*q != 'x') { - if (*q >= '0' && *q <= '9') - ucs += mult * (*q - '0'); - else if (*q >= 'a' && *q <= 'f') - ucs += mult * (*q - 'a' + 10); - else if (*q >= 'A' && *q <= 'F') - ucs += mult * (*q - 'A' + 10); - else - return 0; - mult *= 16; - --q; - } - } else { - // Decimal. - if (!*(p + 2)) return 0; - - const char* q = p + 2; - q = strchr(q, ';'); - - if (!q || !*q) return 0; - - delta = q - p; - --q; - - while (*q != '#') { - if (*q >= '0' && *q <= '9') - ucs += mult * (*q - '0'); - else - return 0; - mult *= 10; - --q; - } - } - if (encoding == TIXML_ENCODING_UTF8) { - // convert the UCS to UTF-8 - ConvertUTF32ToUTF8(ucs, value, length); - } else { - *value = (char)ucs; - *length = 1; - } - return p + delta + 1; - } - - // Now try to match it. - for (i = 0; i < NUM_ENTITY; ++i) { - if (strncmp(entity[i].str, p, entity[i].strLength) == 0) { - assert(strlen(entity[i].str) == entity[i].strLength); - *value = entity[i].chr; - *length = 1; - return (p + entity[i].strLength); - } - } - - // So it wasn't an entity, its unrecognized, or something like that. - *value = *p; // Don't put back the last one, since we return it! - //*length = 1; // Leave unrecognized entities - this doesn't really work. - // Just writes strange XML. - return p + 1; -} - -bool -TiXmlBase::StringEqual(const char* p, const char* tag, bool ignoreCase, TiXmlEncoding encoding) { - assert(p); - assert(tag); - if (!p || !*p) { - assert(0); - return false; - } - - const char* q = p; - - if (ignoreCase) { - while (*q && *tag && ToLower(*q, encoding) == ToLower(*tag, encoding)) { - ++q; - ++tag; - } - - if (*tag == 0) return true; - } else { - while (*q && *tag && *q == *tag) { - ++q; - ++tag; - } - - if (*tag == 0) // Have we found the end of the tag, and everything equal? - return true; - } - return false; -} - -const char* -TiXmlBase::ReadText(const char* p, - TIXML_STRING* text, - bool trimWhiteSpace, - const char* endTag, - bool caseInsensitive, - TiXmlEncoding encoding) { - *text = ""; - if (!trimWhiteSpace // certain tags always keep whitespace - || - !condenseWhiteSpace) // if true, whitespace is always kept - { - // Keep all the white space. - while (p && *p && !StringEqual(p, endTag, caseInsensitive, encoding)) { - int len; - char cArr[4] = { 0, 0, 0, 0 }; - p = GetChar(p, cArr, &len, encoding); - text->append(cArr, len); - } - } else { - bool whitespace = false; - - // Remove leading white space: - p = SkipWhiteSpace(p, encoding); - while (p && *p && !StringEqual(p, endTag, caseInsensitive, encoding)) { - if (*p == '\r' || *p == '\n') { - whitespace = true; - ++p; - } else if (IsWhiteSpace(*p)) { - whitespace = true; - ++p; - } else { - // If we've found whitespace, add it before the - // new character. Any whitespace just becomes a space. - if (whitespace) { - (*text) += ' '; - whitespace = false; - } - int len; - char cArr[4] = { 0, 0, 0, 0 }; - p = GetChar(p, cArr, &len, encoding); - if (len == 1) - (*text) += cArr[0]; // more efficient - else - text->append(cArr, len); - } - } - } - if (p && *p) p += strlen(endTag); - return (p && *p) ? p : 0; -} - -#ifdef TIXML_USE_STL - -void -TiXmlDocument::StreamIn(std::istream* in, TIXML_STRING* tag) { - // The basic issue with a document is that we don't know what we're - // streaming. Read something presumed to be a tag (and hope), then - // identify it, and call the appropriate stream method on the tag. - // - // This "pre-streaming" will never read the closing ">" so the - // sub-tag can orient itself. - - if (!StreamTo(in, '<', tag)) { - SetError(TIXML_ERROR_PARSING_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN); - return; - } - - while (in->good()) { - int tagIndex = (int)tag->length(); - while (in->good() && in->peek() != '>') { - int c = in->get(); - if (c <= 0) { - SetError(TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN); - break; - } - (*tag) += (char)c; - } - - if (in->good()) { - // We now have something we presume to be a node of - // some sort. Identify it, and call the node to - // continue streaming. - TiXmlNode* node = Identify(tag->c_str() + tagIndex, TIXML_DEFAULT_ENCODING); - - if (node) { - node->StreamIn(in, tag); - bool isElement = node->ToElement() != 0; - delete node; - node = 0; - - // If this is the root element, we're done. Parsing will be - // done by the >> operator. - if (isElement) { return; } - } else { - SetError(TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN); - return; - } - } - } - // We should have returned sooner. - SetError(TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN); -} - -#endif - -const char* -TiXmlDocument::Parse(const char* p, TiXmlParsingData* prevData, TiXmlEncoding encoding) { - ClearError(); - - // Parse away, at the document level. Since a document - // contains nothing but other tags, most of what happens - // here is skipping white space. - if (!p || !*p) { - SetError(TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN); - return 0; - } - - // Note that, for a document, this needs to come - // before the while space skip, so that parsing - // starts from the pointer we are given. - location.Clear(); - if (prevData) { - location.row = prevData->cursor.row; - location.col = prevData->cursor.col; - } else { - location.row = 0; - location.col = 0; - } - TiXmlParsingData data(p, TabSize(), location.row, location.col); - location = data.Cursor(); - - if (encoding == TIXML_ENCODING_UNKNOWN) { - // Check for the Microsoft UTF-8 lead bytes. - const unsigned char* pU = (const unsigned char*)p; - if (*(pU + 0) && *(pU + 0) == TIXML_UTF_LEAD_0 && *(pU + 1) && - *(pU + 1) == TIXML_UTF_LEAD_1 && *(pU + 2) && *(pU + 2) == TIXML_UTF_LEAD_2) { - encoding = TIXML_ENCODING_UTF8; - useMicrosoftBOM = true; - } - } - - p = SkipWhiteSpace(p, encoding); - if (!p) { - SetError(TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN); - return 0; - } - - while (p && *p) { - TiXmlNode* node = Identify(p, encoding); - if (node) { - p = node->Parse(p, &data, encoding); - LinkEndChild(node); - } else { - break; - } - - // Did we get encoding info? - if (encoding == TIXML_ENCODING_UNKNOWN && node->ToDeclaration()) { - TiXmlDeclaration* dec = node->ToDeclaration(); - const char* enc = dec->Encoding(); - assert(enc); - - if (*enc == 0) - encoding = TIXML_ENCODING_UTF8; - else if (StringEqual(enc, "UTF-8", true, TIXML_ENCODING_UNKNOWN)) - encoding = TIXML_ENCODING_UTF8; - else if (StringEqual(enc, "UTF8", true, TIXML_ENCODING_UNKNOWN)) - encoding = TIXML_ENCODING_UTF8; // incorrect, but be nice - else - encoding = TIXML_ENCODING_LEGACY; - } - - p = SkipWhiteSpace(p, encoding); - } - - // Was this empty? - if (!firstChild) { - SetError(TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, encoding); - return 0; - } - - // All is well. - return p; -} - -void -TiXmlDocument::SetError(int err, - const char* pError, - TiXmlParsingData* data, - TiXmlEncoding encoding) { - // The first error in a chain is more accurate - don't set again! - if (error) return; - - assert(err > 0 && err < TIXML_ERROR_STRING_COUNT); - error = true; - errorId = err; - errorDesc = errorString[errorId]; - - errorLocation.Clear(); - if (pError && data) { - data->Stamp(pError, encoding); - errorLocation = data->Cursor(); - } -} - -TiXmlNode* -TiXmlNode::Identify(const char* p, TiXmlEncoding encoding) { - TiXmlNode* returnNode = 0; - - p = SkipWhiteSpace(p, encoding); - if (!p || !*p || *p != '<') { return 0; } - - p = SkipWhiteSpace(p, encoding); - - if (!p || !*p) { return 0; } - - // What is this thing? - // - Elements start with a letter or underscore, but xml is reserved. - // - Comments: "; - - if (!StringEqual(p, startTag, false, encoding)) { - if (document) document->SetError(TIXML_ERROR_PARSING_COMMENT, p, data, encoding); - return 0; - } - p += strlen(startTag); - - // [ 1475201 ] TinyXML parses entities in comments - // Oops - ReadText doesn't work, because we don't want to parse the entities. - // p = ReadText( p, &value, false, endTag, false, encoding ); - // - // from the XML spec: - /* - [Definition: Comments may appear anywhere in a document outside other markup; in addition, - they may appear within the document type declaration at places allowed by the - grammar. - They are not part of the document's character data; an XML processor - MAY, but need not, - make it possible for an application to retrieve the text of comments. - For compatibility, - the string "--" (double-hyphen) MUST NOT occur within comments.] - Parameter entity - references MUST NOT be recognized within comments. - - An example of a comment: - - - */ - - value = ""; - // Keep all the white space. - while (p && *p && !StringEqual(p, endTag, false, encoding)) { - value.append(p, 1); - ++p; - } - if (p && *p) p += strlen(endTag); - - return p; -} - -const char* -TiXmlAttribute::Parse(const char* p, TiXmlParsingData* data, TiXmlEncoding encoding) { - p = SkipWhiteSpace(p, encoding); - if (!p || !*p) return 0; - - if (data) { - data->Stamp(p, encoding); - location = data->Cursor(); - } - // Read the name, the '=' and the value. - const char* pErr = p; - p = ReadName(p, &name, encoding); - if (!p || !*p) { - if (document) document->SetError(TIXML_ERROR_READING_ATTRIBUTES, pErr, data, encoding); - return 0; - } - p = SkipWhiteSpace(p, encoding); - if (!p || !*p || *p != '=') { - if (document) document->SetError(TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding); - return 0; - } - - ++p; // skip '=' - p = SkipWhiteSpace(p, encoding); - if (!p || !*p) { - if (document) document->SetError(TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding); - return 0; - } - - const char* end; - const char SINGLE_QUOTE = '\''; - const char DOUBLE_QUOTE = '\"'; - - if (*p == SINGLE_QUOTE) { - ++p; - end = "\'"; // single quote in string - p = ReadText(p, &value, false, end, false, encoding); - } else if (*p == DOUBLE_QUOTE) { - ++p; - end = "\""; // double quote in string - p = ReadText(p, &value, false, end, false, encoding); - } else { - // All attribute values should be in single or double quotes. - // But this is such a common error that the parser will try - // its best, even without them. - value = ""; - while (p && *p // existence - && - !IsWhiteSpace(*p) // whitespace - && - *p != '/' && *p != '>') // tag end - { - if (*p == SINGLE_QUOTE || *p == DOUBLE_QUOTE) { - // [ 1451649 ] Attribute values with trailing quotes not handled correctly - // We did not have an opening quote but seem to have a - // closing one. Give up and throw an error. - if (document) document->SetError(TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding); - return 0; - } - value += *p; - ++p; - } - } - return p; -} - -#ifdef TIXML_USE_STL -void -TiXmlText::StreamIn(std::istream* in, TIXML_STRING* tag) { - while (in->good()) { - int c = in->peek(); - if (!cdata && (c == '<')) { return; } - if (c <= 0) { - TiXmlDocument* document = GetDocument(); - if (document) - document->SetError(TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN); - return; - } - - (*tag) += (char)c; - in->get(); // "commits" the peek made above - - if (cdata && c == '>' && tag->size() >= 3) { - size_t len = tag->size(); - if ((*tag)[len - 2] == ']' && (*tag)[len - 3] == ']') { - // terminator of cdata. - return; - } - } - } -} -#endif - -const char* -TiXmlText::Parse(const char* p, TiXmlParsingData* data, TiXmlEncoding encoding) { - value = ""; - TiXmlDocument* document = GetDocument(); - - if (data) { - data->Stamp(p, encoding); - location = data->Cursor(); - } - - const char* const startTag = ""; - - if (cdata || StringEqual(p, startTag, false, encoding)) { - cdata = true; - - if (!StringEqual(p, startTag, false, encoding)) { - if (document) document->SetError(TIXML_ERROR_PARSING_CDATA, p, data, encoding); - return 0; - } - p += strlen(startTag); - - // Keep all the white space, ignore the encoding, etc. - while (p && *p && !StringEqual(p, endTag, false, encoding)) { - value += *p; - ++p; - } - - TIXML_STRING dummy; - p = ReadText(p, &dummy, false, endTag, false, encoding); - return p; - } else { - bool ignoreWhite = true; - - const char* end = "<"; - p = ReadText(p, &value, ignoreWhite, end, false, encoding); - if (p && *p) return p - 1; // don't truncate the '<' - return 0; - } -} - -#ifdef TIXML_USE_STL -void -TiXmlDeclaration::StreamIn(std::istream* in, TIXML_STRING* tag) { - while (in->good()) { - int c = in->get(); - if (c <= 0) { - TiXmlDocument* document = GetDocument(); - if (document) - document->SetError(TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN); - return; - } - (*tag) += (char)c; - - if (c == '>') { - // All is well. - return; - } - } -} -#endif - -const char* -TiXmlDeclaration::Parse(const char* p, TiXmlParsingData* data, TiXmlEncoding _encoding) { - p = SkipWhiteSpace(p, _encoding); - // Find the beginning, find the end, and look for - // the stuff in-between. - TiXmlDocument* document = GetDocument(); - if (!p || !*p || !StringEqual(p, "SetError(TIXML_ERROR_PARSING_DECLARATION, 0, 0, _encoding); - return 0; - } - if (data) { - data->Stamp(p, _encoding); - location = data->Cursor(); - } - p += 5; - - version = ""; - encoding = ""; - standalone = ""; - - while (p && *p) { - if (*p == '>') { - ++p; - return p; - } - - p = SkipWhiteSpace(p, _encoding); - if (StringEqual(p, "version", true, _encoding)) { - TiXmlAttribute attrib; - p = attrib.Parse(p, data, _encoding); - version = attrib.Value(); - } else if (StringEqual(p, "encoding", true, _encoding)) { - TiXmlAttribute attrib; - p = attrib.Parse(p, data, _encoding); - encoding = attrib.Value(); - } else if (StringEqual(p, "standalone", true, _encoding)) { - TiXmlAttribute attrib; - p = attrib.Parse(p, data, _encoding); - standalone = attrib.Value(); - } else { - // Read over whatever it is. - while (p && *p && *p != '>' && !IsWhiteSpace(*p)) ++p; - } - } - return 0; -} - -bool -TiXmlText::Blank() const { - for (unsigned i = 0; i < value.length(); i++) - if (!IsWhiteSpace(value[i])) return false; - return true; -} diff --git a/cmake/find_sources.cmake b/cmake/find_sources.cmake deleted file mode 100644 index 900a3da..0000000 --- a/cmake/find_sources.cmake +++ /dev/null @@ -1,28 +0,0 @@ -## Copyright 2016 Etix Labs -## -## Licensed under the Apache License, Version 2.0 (the "License"); -## you may not use this file except in compliance with the License. -## You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. - -# function to retrieve files sources inside a list of folders -function(find_sources DIRS) - set(_headers "") - set(_srcs "") - foreach (dir ${ARGV}) - file (GLOB h_${dir} "${dir}/*.h") - file (GLOB s_${dir} "${dir}/*.c*") - source_group (${dir} FILES ${s_${dir}} ${h_${dir}}) - set (_srcs ${_srcs} ${s_${dir}}) - set (_headers ${_headers} ${h_${dir}}) - endforeach () - set (SOURCES ${_srcs} PARENT_SCOPE) - set (HEADERS ${_headers} PARENT_SCOPE) -endfunction() diff --git a/cmake/jsoncpp.cmake b/cmake/jsoncpp.cmake deleted file mode 100644 index 12ddf8b..0000000 --- a/cmake/jsoncpp.cmake +++ /dev/null @@ -1,47 +0,0 @@ -## Copyright 2016 Etix Labs -## -## Licensed under the Apache License, Version 2.0 (the "License"); -## you may not use this file except in compliance with the License. -## You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. - -cmake_minimum_required(VERSION 2.8.8) -include(ExternalProject) - -message(STATUS "Configuring deps.jsoncpp") - -set(JSONCPP_DIR jsoncpp) -set(JSONCPP_PATH ${DEPS_DIR}/${JSONCPP_DIR}) - -ExternalProject_Add( - deps.jsoncpp - PREFIX ${JSONCPP_PATH} - GIT_REPOSITORY https://github.com/open-source-parsers/jsoncpp.git - TIMEOUT 10 - CONFIGURE_COMMAND ${CMAKE_COMMAND} "-DCMAKE_INSTALL_PREFIX=${JSONCPP_PATH}" -DBUILD_TYPE=Release -DBUILD_STATIC_LIBS=OFF -DBUILD_SHARED_LIBS=ON -DJSONCPP_WITH_TESTS=OFF -DJSONCPP_WITH_POST_BUILD_UNITTEST=OFF - BUILD_IN_SOURCE ON - UPDATE_COMMAND "" - BUILD_COMMAND ${CMAKE_MAKE_PROGRAM} - INSTALL_COMMAND "" - LOG_DOWNLOAD ON - LOG_UPDATE ON - LOG_CONFIGURE ON - LOG_BUILD ON -) - -ExternalProject_Get_Property(deps.jsoncpp SOURCE_DIR) - -set (JSONCPP_INCLUDE_DIR "${SOURCE_DIR}/include" PARENT_SCOPE) -set (JSONCPP_LIBRARY_DIR "${SOURCE_DIR}/src/lib_json") -set (JSONCPP_LIBRARY_DIR ${JSONCPP_LIBRARY_DIR} PARENT_SCOPE) - -file(GLOB JSONCPP_INSTALL_DEPENDENCIES "${JSONCPP_LIBRARY_DIR}/${CMAKE_SHARED_LIBRARY_PREFIX}jsoncpp${CMAKE_SHARED_LIBRARY_SUFFIX}*") -list (APPEND CAMERADAR_INSTALL_DEPENDENCIES ${JSONCPP_INSTALL_DEPENDENCIES}) -set(CAMERADAR_INSTALL_DEPENDENCIES ${CAMERADAR_INSTALL_DEPENDENCIES} PARENT_SCOPE) diff --git a/cmake/mysql_connector.cmake b/cmake/mysql_connector.cmake deleted file mode 100644 index 8240520..0000000 --- a/cmake/mysql_connector.cmake +++ /dev/null @@ -1,50 +0,0 @@ -## Copyright 2016 Etix Labs -## -## Licensed under the Apache License, Version 2.0 (the "License"); -## you may not use this file except in compliance with the License. -## You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. - -# MySQL Connector dependency -message(STATUS "Configuring deps.mysqlconnector") - -set (MYSQL_CONNECTOR_VERSION 1.1.6) -set (MD5 9e49dcfc1408b18b3d3ca02781ff7efb) -set (MYSQL_CONNECTOR_DIR mysql-connector) -set (MYSQL_CONNECTOR_PATH ${DEPS_DIR}/${MYSQL_CONNECTOR_DIR}) - -set (BOOST_ROOT_DIR ${DEPS_DIR}/boost/src/deps.boost) - -# include(ExternalProject) -ExternalProject_Add( - deps.mysql_connector - PREFIX ${MYSQL_CONNECTOR_PATH} - URL http://dev.mysql.com/get/Downloads/Connector-C++/mysql-connector-c++-${MYSQL_CONNECTOR_VERSION}.tar.gz - URL_HASH MD5=${MD5} - CONFIGURE_COMMAND ${CMAKE_COMMAND} -DBOOST_ROOT=${BOOST_ROOT_DIR} "-DCMAKE_INSTALL_PREFIX=${MYSQL_CONNECTOR_PATH}" -DBUILD_TYPE=Release -DMYSQL_CXXFLAGS=-fexceptions - BUILD_IN_SOURCE ON - UPDATE_COMMAND "" - BUILD_COMMAND ${CMAKE_MAKE_PROGRAM} - INSTALL_COMMAND ${CMAKE_MAKE_PROGRAM} install - LOG_DOWNLOAD ON - LOG_UPDATE ON - LOG_CONFIGURE ON - LOG_BUILD ON -) - -set (MYSQL_CONNECTOR_INCLUDE_DIR "${MYSQL_CONNECTOR_PATH}/include" PARENT_SCOPE) -set (MYSQL_CONNECTOR_LIBRARY_DIR "${MYSQL_CONNECTOR_PATH}/lib") - -set (MYSQL_CONNECTOR_LIBRARY_DIR ${MYSQL_CONNECTOR_LIBRARY_DIR} PARENT_SCOPE) - -# list all the mysql libraries -file(GLOB MYSQL_CONNECTOR_INSTALL_DEPENDENCIES "${MYSQL_CONNECTOR_LIBRARY_DIR}/${CMAKE_SHARED_LIBRARY_PREFIX}mysqlcppconn${CMAKE_SHARED_LIBRARY_SUFFIX}*") -list (APPEND CAMERADAR_INSTALL_DEPENDENCIES ${MYSQL_CONNECTOR_INSTALL_DEPENDENCIES}) -set(CAMERADAR_INSTALL_DEPENDENCIES ${CAMERADAR_INSTALL_DEPENDENCIES} PARENT_SCOPE) diff --git a/deployment/Dockerfile b/deployment/Dockerfile deleted file mode 100644 index f0359de..0000000 --- a/deployment/Dockerfile +++ /dev/null @@ -1,27 +0,0 @@ -FROM ubuntu:16.04 - -MAINTAINER brendan.leglaunec@etixgroup.com - -ENV LD_LIBRARY_PATH="/cameradar/libraries" - -RUN apt-get update && apt-get install -y \ - nmap \ - ffmpeg \ - libboost-all-dev \ - libgstreamer1.0-dev \ - gstreamer1.0-plugins-base \ - gstreamer1.0-plugins-good \ - libcurl4-openssl-dev \ - libmysqlclient20 \ - mysql-client - -ADD cameradar_*_Release_Linux.tar.gz / -RUN mv cameradar_*_Release_Linux cameradar - -COPY conf /cameradar/conf - -COPY docker-entrypoint.sh /usr/local/bin/ -RUN ln -s /usr/local/bin/docker-entrypoint.sh /entrypoint.sh -ENTRYPOINT ["docker-entrypoint.sh"] - -CMD ["/cameradar/bin/cameradar", "-c", "/cameradar/conf/cameradar.conf.json"] diff --git a/deployment/build_last_package.sh b/deployment/build_last_package.sh deleted file mode 100755 index 12434c2..0000000 --- a/deployment/build_last_package.sh +++ /dev/null @@ -1,55 +0,0 @@ -#!/usr/bin/env bash - -ESC_SEQ="\x1b[" -COL_RESET=$ESC_SEQ"39;49;00m" -COL_RED=$ESC_SEQ"31;01m" -COL_GREEN=$ESC_SEQ"32;01m" -COL_YELLOW=$ESC_SEQ"33;01m" - -echo -e $COL_YELLOW"Deleting old package ... "$COL_RESET -rm -f cameradar_*_${1:-"Release"}_Linux.tar.gz -echo -e $COL_GREEN"OK!"$COL_RESET - -echo -e $COL_YELLOW"Creating package ... "$COL_RESET - -cd .. -ret=$? -if [ "$ret" -ne "0" ]; then - echo -e $COL_RED"KO!"$COL_RESET; - exit 1; -fi - -mkdir build - -cd build -ret=$? -if [ "$ret" -ne "0" ]; then - echo -e $COL_RED"KO!"$COL_RESET; - exit 1; -fi - -rm -f cameradar_*_${1:-"Release"}_Linux.tar.gz - -cmake .. -DCMAKE_BUILD_TYPE=${1:-"Release"} -ret=$? -if [ "$ret" -ne "0" ]; then - echo -e $COL_RED"KO!"$COL_RESET; - exit 1; -fi - -make package -ret=$? -if [ "$ret" -ne "0" ]; then - echo -e $COL_RED"KO!"$COL_RESET; - exit 1; -fi - -cp cameradar_*_${1:-"Release"}_Linux.tar.gz ../deployment - -cd ../deployment -ret=$? -if [ "$ret" -ne "0" ]; then - echo -e $COL_RED"KO!"$COL_RESET; - exit 1; -fi -echo -e $COL_GREEN"OK!"$COL_RESET diff --git a/deployment/cameradar_1.1.4_Release_Linux.tar.gz b/deployment/cameradar_1.1.4_Release_Linux.tar.gz deleted file mode 100644 index 380e6af..0000000 Binary files a/deployment/cameradar_1.1.4_Release_Linux.tar.gz and /dev/null differ diff --git a/deployment/conf/cameradar.tmpl.conf.json b/deployment/conf/cameradar.tmpl.conf.json deleted file mode 100644 index c883f74..0000000 --- a/deployment/conf/cameradar.tmpl.conf.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "mysql_db" : { - "host" : "cameradar-database", - "port" : 3306, - "user": "root", - "password": "$MYSQL_ROOT_PASSWORD", - "db_name": "cmrdr" - }, - "target" : "$CAMERAS_TARGET", - "ports" : "$CAMERAS_PORTS", - "rtsp_url_file" : "/cameradar/conf/url.json", - "rtsp_ids_file" : "/cameradar/conf/ids.json", - "thumbnail_storage_path" : "/tmp/thumbs", - "cache_manager_path" : "/cameradar/cache_managers", - "cache_manager_name" : "$CACHE_MANAGER" -} diff --git a/deployment/conf/ids.json b/deployment/conf/ids.json deleted file mode 100644 index 046b60c..0000000 --- a/deployment/conf/ids.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "username": [ - "", - "admin", - "Admin", - "root", - "supervisor", - "ubnt" - ], - "password" : [ - "", - "admin", - "9999", - "123456", - "pass", - "camera", - "1234", - "12345", - "fliradmin", - "system", - "jvc", - "meinsm", - "root", - "4321", - "1111111", - "password", - "ikwd", - "supervisor", - "ubnt" - ] -} \ No newline at end of file diff --git a/deployment/conf/url.json b/deployment/conf/url.json deleted file mode 100644 index 23af730..0000000 --- a/deployment/conf/url.json +++ /dev/null @@ -1,117 +0,0 @@ -{ - "urls" : [ - "/", - "/1.AMP", - "/1/stream1", - "/CAM_ID.password.mp2", - "/GetData.cgi", - "/MediaInput/h264", - "/MediaInput/mpeg4", - "/VideoInput/1/h264/1", - "/access_code", - "/access_name_for_stream_1_to_5", - "/av0_0", - "/av2", - "/avn=2", - "/axis-media/media.amp", - "/cam", - "/cam0_0", - "/cam0_1", - "/cam1/h264", - "/cam1/h264/multicast", - "/cam1/mjpeg", - "/cam1/mpeg4", - "/camera.stm", - "/ch0", - "/ch001.sdp", - "/ch01.264", - "/ch0_unicast_firststream", - "/ch0_unicast_secondstream", - "/channel1", - "/h264", - "/h264/media.amp", - "/image.mpg", - "/img/media.sav", - "/img/video.asf", - "/img/video.sav", - "/ioImage/1", - "/ipcam.sdp", - "/ipcam_h264.sdp", - "/live.sdp", - "/live/h264", - "/live/mpeg4", - "/live_mpeg4.sdp", - "/livestream", - "/livestream/", - "/media/media.amp", - "/media/video1", - "/mjpeg/media.smp", - "/mp4", - "/mpeg4", - "/mpeg4/1/media.amp", - "/mpeg4/media.amp", - "/mpeg4/media.smp", - "/mpeg4unicast", - "/mpg4/rtsp.amp", - "/multicaststream", - "/now.mp4", - "/nph-h264.cgi", - "/nphMpeg4/g726-640x", - "/nphMpeg4/g726-640x480", - "/nphMpeg4/nil-320x240", - "/play1.sdp", - "/play2.sdp", - "/rtpvideo1.sdp", - "/rtsp_live0", - "/rtsp_live1", - "/rtsp_live2", - "/rtsp_tunnel", - "/rtsph264", - "/stream1", - "/user.pin.mp2", - "/user_defined", - "/video", - "/video.3gp", - "/video.mp4", - "/video1", - "/video1+audio1", - "/vis", - "/wfov", - "/video.h264", - "/11", - "/12", - "/ch1-s1", - "/live3.sdp", - "/onvif-media/media.amp", - "/axis-media/media.amp", - "/axis-media/media.amp?videocodec=h264", - "/mpeg4/media.amp", - "/stream", - "/cam/realmonitor", - "/live", - "/video.pro2", - "/videoMain", - "/VideoInput/1/mpeg4/1", - "/VideoInput/1/h264/1", - "/video.pro3", - "/video.pro1", - "/video.mjpg", - "/h264_vga.sdp", - "/media.amp", - "/media", - "/ONVIF/MediaInput", - "/nphMpeg4/g726-640x48", - "/MediaInput/mpeg4", - "/MediaInput/h264", - "/Streaming/Channels/1", - "/ch0_0.h264", - "/rtsph2641080p", - "/live/av0", - "/cam1/onvif-h264", - "/ucast/11", - "/LowResolutionVideo", - "/1", - "/live/ch00_0", - "/medias2" - ] -} diff --git a/deployment/docker-compose.yml b/deployment/docker-compose.yml deleted file mode 100644 index ade7448..0000000 --- a/deployment/docker-compose.yml +++ /dev/null @@ -1,25 +0,0 @@ -version: '2' - -services: - cameradar: - build: . - container_name: cameradar - volumes: - - "./cameradar_thumbnails:/tmp/thumbs" - - ".:/tmp/shared" - environment: - - CAMERAS_TARGET=localhost - - CAMERAS_PORTS=554,8554 - - CACHE_MANAGER=dumb - - MYSQL_ROOT_PASSWORD=root - cameradar-database: - container_name: cameradar-database - image: mysql:5.7 - environment: - - MYSQL_ROOT_PASSWORD=root - - MYSQL_DATABASE=cmrdr - ports: - - "3306:3306" - -volumes: - mysql_data: diff --git a/deployment/docker-entrypoint.sh b/deployment/docker-entrypoint.sh deleted file mode 100755 index aeac541..0000000 --- a/deployment/docker-entrypoint.sh +++ /dev/null @@ -1,48 +0,0 @@ -#!/bin/bash - -ESC_SEQ="\x1b[" -COL_RESET=$ESC_SEQ"39;49;00m" -COL_GREEN=$ESC_SEQ"32;01m" - -# if command starts with an option, prepend /cameradar/bin/cameradar -if [ "${1:0:1}" = '-' ]; then - set -- /cameradar/bin/cameradar "$@" -fi - -# skip setup if they want an option that stops cameradar -wantHelp= -for arg; do - case "$arg" in - -v|-h) - wantHelp=1 - break - ;; - esac -done - -if [ "$CACHE_MANAGER" == "" ]; then - export CACHE_MANAGER="dumb" -fi - -if [ "$CAMERAS_TARGET" == "" ]; then - export CAMERAS_TARGET="0.0.0.0" -fi - -if [ "$CAMERAS_PORTS" == "" ]; then - export CAMERAS_PORTS="554,8554" -fi - -envsubst < /cameradar/conf/cameradar.tmpl.conf.json > /cameradar/conf/cameradar.conf.json - - -if [ "$CACHE_MANAGER" == "mysql" ] && [ "$1" = '/cameradar/bin/cameradar' -a -z "$wantHelp" ]; then - echo -n "Waiting for cameradar-database to be ready..." - while ! mysqladmin ping -h "cameradar-database" -P3306 --silent; do - sleep 1; echo -n "." - done - echo -e $COL_GREEN"ok"$COL_RESET - - echo "Cameradar init finished. Starting it." -fi - -exec "$@" diff --git a/deps/CMakeLists.txt b/deps/CMakeLists.txt deleted file mode 100644 index 9c4c276..0000000 --- a/deps/CMakeLists.txt +++ /dev/null @@ -1,23 +0,0 @@ -## Copyright 2016 Etix Labs -## -## Licensed under the Apache License, Version 2.0 (the "License"); -## you may not use this file except in compliance with the License. -## You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. - -cmake_minimum_required (VERSION 2.8.1) - -# Lib subdirectory - -include (jsoncpp) -include (mysql_connector) - -set_directory_properties(PROPERTIES CLEAN_NO_CUSTOM ON) -set (CAMERADAR_INSTALL_DEPENDENCIES ${CAMERADAR_INSTALL_DEPENDENCIES} PARENT_SCOPE) diff --git a/deps/licenses/boost.txt b/deps/licenses/boost.txt deleted file mode 100644 index 127a5bc..0000000 --- a/deps/licenses/boost.txt +++ /dev/null @@ -1,23 +0,0 @@ -Boost Software License - Version 1.0 - August 17th, 2003 - -Permission is hereby granted, free of charge, to any person or organization -obtaining a copy of the software and accompanying documentation covered by -this license (the "Software") to use, reproduce, display, distribute, -execute, and transmit the Software, and to prepare derivative works of the -Software, and to permit third-parties to whom the Software is furnished to -do so, all subject to the following: - -The copyright notices in the Software and this entire statement, including -the above license grant, this restriction and the following disclaimer, -must be included in all copies of the Software, in whole or in part, and -all derivative works of the Software, unless such copies or derivative -works are solely in the form of machine-executable object code generated by -a source language processor. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT -SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE -FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/deps/licenses/jsoncpp.txt b/deps/licenses/jsoncpp.txt deleted file mode 100644 index efaf022..0000000 --- a/deps/licenses/jsoncpp.txt +++ /dev/null @@ -1,55 +0,0 @@ -The JsonCpp library's source code, including accompanying documentation, -tests and demonstration applications, are licensed under the following -conditions... - -The author (Baptiste Lepilleur) explicitly disclaims copyright in all -jurisdictions which recognize such a disclaimer. In such jurisdictions, -this software is released into the Public Domain. - -In jurisdictions which do not recognize Public Domain property (e.g. Germany as of -2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur, and is -released under the terms of the MIT License (see below). - -In jurisdictions which recognize Public Domain property, the user of this -software may choose to accept it either as 1) Public Domain, 2) under the -conditions of the MIT License (see below), or 3) under the terms of dual -Public Domain/MIT License conditions described here, as they choose. - -The MIT License is about as close to Public Domain as a license can get, and is -described in clear, concise terms at: - - http://en.wikipedia.org/wiki/MIT_License - -The full text of the MIT License follows: - -======================================================================== -Copyright (c) 2007-2010 Baptiste Lepilleur - -Permission is hereby granted, free of charge, to any person -obtaining a copy of this software and associated documentation -files (the "Software"), to deal in the Software without -restriction, including without limitation the rights to use, copy, -modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -======================================================================== -(END LICENSE TEXT) - -The MIT license is compatible with both the GPL and commercial -software, affording one all of the rights of Public Domain with the -minor nuisance of being required to keep the above copyright notice -and license text in the source code. Note also that by accepting the -Public Domain "license" you can re-license your copy using whatever -license you like. \ No newline at end of file diff --git a/test/conf/ids.json b/dictionaries/credentials.json similarity index 90% rename from test/conf/ids.json rename to dictionaries/credentials.json index 046b60c..d2d49a2 100644 --- a/test/conf/ids.json +++ b/dictionaries/credentials.json @@ -1,5 +1,5 @@ { - "username": [ + "usernames": [ "", "admin", "Admin", @@ -7,7 +7,7 @@ "supervisor", "ubnt" ], - "password" : [ + "passwords" : [ "", "admin", "9999", diff --git a/dictionaries/routes b/dictionaries/routes new file mode 100644 index 0000000..623ab75 --- /dev/null +++ b/dictionaries/routes @@ -0,0 +1,113 @@ + +1.AMP +1/stream1 +CAM_ID.password.mp2 +GetData.cgi +MediaInput/h264 +MediaInput/mpeg4 +VideoInput/1/h264/1 +access_code +access_name_for_stream_1_to_5 +av0_0 +av2 +avn=2 +axis-media/media.amp +cam +cam0_0 +cam0_1 +cam1/h264 +cam1/h264/multicast +cam1/mjpeg +cam1/mpeg4 +camera.stm +ch0 +ch001.sdp +ch01.264 +ch0_unicast_firststream +ch0_unicast_secondstream +channel1 +h264 +h264/media.amp +image.mpg +img/media.sav +img/video.asf +img/video.sav +ioImage/1 +ipcam.sdp +ipcam_h264.sdp +live.sdp +live/h264 +live/mpeg4 +live_mpeg4.sdp +livestream +livestream/ +media/media.amp +media/video1 +mjpeg/media.smp +mp4 +mpeg4 +mpeg4/1/media.amp +mpeg4/media.amp +mpeg4/media.smp +mpeg4unicast +mpg4/rtsp.amp +multicaststream +now.mp4 +nph-h264.cgi +nphMpeg4/g726-640x +nphMpeg4/g726-640x480 +nphMpeg4/nil-320x240 +play1.sdp +play2.sdp +rtpvideo1.sdp +rtsp_live0 +rtsp_live1 +rtsp_live2 +rtsp_tunnel +rtsph264 +stream1 +user.pin.mp2 +user_defined +video +video.3gp +video.mp4 +video1 +video1+audio1 +vis +wfov +video.h264 +11 +12 +ch1-s1 +live3.sdp +onvif-media/media.amp +axis-media/media.amp +axis-media/media.amp?videocodec=h264 +mpeg4/media.amp +stream +cam/realmonitor +live +video.pro2 +videoMain +VideoInput/1/mpeg4/1 +VideoInput/1/h264/1 +video.pro3 +video.pro1 +video.mjpg +h264_vga.sdp +media.amp +media +ONVIF/MediaInput +nphMpeg4/g726-640x48 +MediaInput/mpeg4 +MediaInput/h264 +Streaming/Channels/1 +ch0_0.h264 +rtsph2641080p +live/av0 +cam1/onvif-h264 +ucast/11 +LowResolutionVideo +1 +live/ch00_0 +medias2 \ No newline at end of file diff --git a/images/AttackCredentials.png b/images/AttackCredentials.png new file mode 100644 index 0000000..4dc6285 Binary files /dev/null and b/images/AttackCredentials.png differ diff --git a/images/AttackRoute.png b/images/AttackRoute.png new file mode 100644 index 0000000..49d9a58 Binary files /dev/null and b/images/AttackRoute.png differ diff --git a/images/Discover.png b/images/Discover.png new file mode 100644 index 0000000..e1f811f Binary files /dev/null and b/images/Discover.png differ diff --git a/images/LoadCredentials.png b/images/LoadCredentials.png new file mode 100644 index 0000000..a2d4672 Binary files /dev/null and b/images/LoadCredentials.png differ diff --git a/images/LoadRoutes.png b/images/LoadRoutes.png new file mode 100644 index 0000000..25e9d9e Binary files /dev/null and b/images/LoadRoutes.png differ diff --git a/images/Models.png b/images/Models.png new file mode 100644 index 0000000..37b1ec7 Binary files /dev/null and b/images/Models.png differ diff --git a/images/NmapPresets.png b/images/NmapPresets.png new file mode 100644 index 0000000..75edb2c Binary files /dev/null and b/images/NmapPresets.png differ diff --git a/images/Output.png b/images/Output.png new file mode 100644 index 0000000..77f7f7a Binary files /dev/null and b/images/Output.png differ diff --git a/images/ParseNmapResults.png b/images/ParseNmapResults.png new file mode 100644 index 0000000..f7842b2 Binary files /dev/null and b/images/ParseNmapResults.png differ diff --git a/images/RTSPURL.png b/images/RTSPURL.png new file mode 100644 index 0000000..4fa083f Binary files /dev/null and b/images/RTSPURL.png differ diff --git a/images/RunNmap.png b/images/RunNmap.png new file mode 100644 index 0000000..a9d0bc5 Binary files /dev/null and b/images/RunNmap.png differ diff --git a/test/Dockerfile b/test/Dockerfile deleted file mode 100644 index 27636f7..0000000 --- a/test/Dockerfile +++ /dev/null @@ -1,42 +0,0 @@ -FROM ubuntu:15.10 - -MAINTAINER brendan.leglaunec@etixgroup.com - -ENV LD_LIBRARY_PATH="/cameradar/libraries" - -# Manually install go -RUN apt-get update && apt-get install -y make git wget curl -RUN wget https://storage.googleapis.com/golang/go1.6.linux-amd64.tar.gz -RUN tar -C /usr/local -xzf go1.6.linux-amd64.tar.gz - -ENV GOPATH=/cameradartest/go -ENV PATH=$PATH:/go/bin -ENV PATH=$PATH:/usr/local/go/bin -ENV LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib - -RUN apt-get update && apt-get install -y \ - nmap \ - libmysqlclient18 \ - ffmpeg \ - mysql-client \ - libgstreamer1.0-dev \ - gstreamer1.0-plugins-base \ - gstreamer1.0-plugins-good \ - libcurl4-openssl-dev - -RUN apt-get install -y psmisc - -ADD cameradar_*_Debug_Linux.tar.gz / -RUN mv cameradar_*_Debug_Linux cameradar - -RUN mkdir -p /cameradartest/go/src/cameradartest -COPY src/*.go /cameradartest/go/src/cameradartest/ -COPY ./conf /conf -ADD ./docker/run_cameradartest.sh /run.sh - -RUN go get github.com/go-sql-driver/mysql - -RUN mkdir /thumbnails -WORKDIR /cameradartest/go/src/cameradartest -RUN go build -o cameradartest *.go -CMD ["/run.sh"] diff --git a/test/Dockerfile-camera b/test/Dockerfile-camera deleted file mode 100644 index bb68034..0000000 --- a/test/Dockerfile-camera +++ /dev/null @@ -1,22 +0,0 @@ -FROM ubuntu:16.04 -MAINTAINER brendan.leglaunec@etixgroup.com - -RUN apt-get update && apt-get install -y \ - libgstrtspserver-1.0-dev \ - libgstreamer1.0-dev \ - gstreamer1.0-plugins-base \ - gstreamer1.0-plugins-bad \ - gstreamer1.0-plugins-ugly \ - gstreamer1.0-libav \ - gstreamer1.0-tools \ - libssl-dev mysql-client \ - gstreamer1.0-plugins-good \ - libgstreamer-plugins-base1.0-dev \ - libgstreamer-plugins-bad1.0-dev - -COPY ./docker/run_ces.sh /start.sh -COPY ./camera_emulation_server /camera_emulation_server - -EXPOSE 8554 - -RUN ./camera_emulation_server& diff --git a/test/build_last_package.sh b/test/build_last_package.sh deleted file mode 100755 index 07517d6..0000000 --- a/test/build_last_package.sh +++ /dev/null @@ -1,55 +0,0 @@ -#!/usr/bin/env bash - -ESC_SEQ="\x1b[" -COL_RESET=$ESC_SEQ"39;49;00m" -COL_RED=$ESC_SEQ"31;01m" -COL_GREEN=$ESC_SEQ"32;01m" -COL_YELLOW=$ESC_SEQ"33;01m" - -echo -e $COL_YELLOW"Deleting old package ... "$COL_RESET -rm -f cameradar_*_${1:-"Release"}_Linux.tar.gz -echo -e $COL_GREEN"OK!"$COL_RESET - -echo -e $COL_YELLOW"Creating package ... "$COL_RESET - -cd .. -ret=$? -if [ "$ret" -ne "0" ]; then - echo -e $COL_RED"KO!"$COL_RESET; - exit 1; -fi - -mkdir build - -cd build -ret=$? -if [ "$ret" -ne "0" ]; then - echo -e $COL_RED"KO!"$COL_RESET; - exit 1; -fi - -rm -f cameradar_*_${1:-"Release"}_Linux.tar.gz - -cmake .. -DCMAKE_BUILD_TYPE=${1:-"Release"} -ret=$? -if [ "$ret" -ne "0" ]; then - echo -e $COL_RED"KO!"$COL_RESET; - exit 1; -fi - -make package -ret=$? -if [ "$ret" -ne "0" ]; then - echo -e $COL_RED"KO!"$COL_RESET; - exit 1; -fi - -cp cameradar_*_${1:-"Release"}_Linux.tar.gz ../test - -cd ../test -ret=$? -if [ "$ret" -ne "0" ]; then - echo -e $COL_RED"KO!"$COL_RESET; - exit 1; -fi -echo -e $COL_GREEN"OK!"$COL_RESET diff --git a/test/camera_emulation_server b/test/camera_emulation_server deleted file mode 100755 index fc6d6e1..0000000 Binary files a/test/camera_emulation_server and /dev/null differ diff --git a/test/conf/cameradar.conf.json b/test/conf/cameradar.conf.json deleted file mode 100644 index d4bb27f..0000000 --- a/test/conf/cameradar.conf.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "mysql_db" : { - "host" : "cameradar-database", - "port" : 3306, - "user": "root", - "password": "root", - "db_name": "cmrdr" - }, - "target" : "localhost", - "ports" : "554,8554", - "rtsp_url_file" : "/conf/url.json", - "rtsp_ids_file" : "/conf/ids.json", - "thumbnail_storage_path" : "/tmp", - "cache_manager_path" : "/cameradar/cache_managers", - "cache_manager_name" : "dumb" -} diff --git a/test/conf/cameratest.conf.json b/test/conf/cameratest.conf.json deleted file mode 100644 index f506f1e..0000000 --- a/test/conf/cameratest.conf.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "Output": "cameratest.log.xml", - - "Cameradar" : { - "Path": "/cameradar/cameradar_standalone/cameradar", - "Args": "-s 172.17.0.0/24 -c /conf/cameradar.conf.json --gst-rtsp-server", - "Ports": "554,5554,8554", - "IdsPath": "/conf/ids.json", - "RoutesPath": "/conf/url.json", - "ThumbPath": "/tmp", - "dbHost": "cameradar-database", - "dbPort": 3306, - "dbUser": "root", - "dbPassword": "root", - "dbName": "cmrdr", - "Console": false - }, - "Tests" : [ - { - "address" : "127.0.0.1", - "password" : "", - "port" : "8554", - "route" : "live.sdp", - "username" : "", - "valid" : true - }, - { - "address" : "172.16.100.11", - "password" : "", - "port" : "553", - "route" : "live.sdp", - "username" : "admin", - "valid" : false - }, - { - "address" : "172.16.100.13", - "password" : "", - "port" : "554", - "route" : "live.sdp", - "username" : "admin", - "valid" : true - } - ] -} diff --git a/test/conf/url.json b/test/conf/url.json deleted file mode 100644 index 31d250c..0000000 --- a/test/conf/url.json +++ /dev/null @@ -1,77 +0,0 @@ -{ - "urls" : [ - "/", - "/1.AMP", - "/1/stream1", - "/CAM_ID.password.mp2", - "/GetData.cgi", - "/MediaInput/h264", - "/MediaInput/mpeg4", - "/VideoInput/1/h264/1", - "/access_code", - "/access_name_for_stream_1_to_5", - "/av0_0", - "/av2", - "/avn=2", - "/axis-media/media.amp", - "/cam", - "/cam0_0", - "/cam0_1", - "/cam1/h264", - "/cam1/h264/multicast", - "/cam1/mjpeg", - "/cam1/mpeg4", - "/camera.stm", - "/ch0", - "/ch001.sdp", - "/ch0_unicast_firststream", - "/ch0_unicast_secondstream", - "/channel1", - "/h264", - "/h264/media.amp", - "/image.mpg", - "/img/media.sav", - "/img/video.asf", - "/img/video.sav", - "/ioImage/1", - "/ipcam.sdp", - "/ipcam_h264.sdp", - "/live.sdp", - "/live/h264", - "/live/mpeg4", - "/live_mpeg4.sdp", - "/livestream", - "/livestream/", - "/media/media.amp", - "/media/video1", - "/mjpeg/media.smp", - "/mp4", - "/mpeg4", - "/mpeg4/1/media.amp", - "/mpeg4/media.amp", - "/mpeg4/media.smp", - "/mpeg4unicast", - "/mpg4/rtsp.amp", - "/multicaststream", - "/now.mp4", - "/nph-h264.cgi", - "/nphMpeg4/g726-640x", - "/nphMpeg4/g726-640x480", - "/nphMpeg4/nil-320x240", - "/play1.sdp", - "/play2.sdp", - "/rtpvideo1.sdp", - "/rtsp_tunnel", - "/rtsph264", - "/stream1", - "/user.pin.mp2", - "/user_defined", - "/video", - "/video.3gp", - "/video.mp4", - "/video1", - "/video1+audio1", - "/vis", - "/wfov" - ] -} diff --git a/test/docker/cameratest.conf.tmpl.json b/test/docker/cameratest.conf.tmpl.json deleted file mode 100644 index e488a79..0000000 --- a/test/docker/cameratest.conf.tmpl.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "output": "test-results.xml", - - "cameradar" : { - "path": "/cameradar/bin/cameradar", - "args": "-s 172.17.0.0/24 -c /conf/cameradar.conf.json --gst-rtsp-server", - "ports": "554,5554,8554", - "ids_path": "conf/ids.json", - "routes_path": "conf/url.json", - "thumb_path": "/tmp", - "db_host": "cameradar-database", - "db_port": 3306, - "db_user": "root", - "db_password": "root", - "db_name": "cmrdr", - "console": false - }, - "tests" : __CAMERAS__ -} diff --git a/test/docker/conf/ids.json b/test/docker/conf/ids.json deleted file mode 100644 index 046b60c..0000000 --- a/test/docker/conf/ids.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "username": [ - "", - "admin", - "Admin", - "root", - "supervisor", - "ubnt" - ], - "password" : [ - "", - "admin", - "9999", - "123456", - "pass", - "camera", - "1234", - "12345", - "fliradmin", - "system", - "jvc", - "meinsm", - "root", - "4321", - "1111111", - "password", - "ikwd", - "supervisor", - "ubnt" - ] -} \ No newline at end of file diff --git a/test/docker/conf/url.json b/test/docker/conf/url.json deleted file mode 100644 index 31d250c..0000000 --- a/test/docker/conf/url.json +++ /dev/null @@ -1,77 +0,0 @@ -{ - "urls" : [ - "/", - "/1.AMP", - "/1/stream1", - "/CAM_ID.password.mp2", - "/GetData.cgi", - "/MediaInput/h264", - "/MediaInput/mpeg4", - "/VideoInput/1/h264/1", - "/access_code", - "/access_name_for_stream_1_to_5", - "/av0_0", - "/av2", - "/avn=2", - "/axis-media/media.amp", - "/cam", - "/cam0_0", - "/cam0_1", - "/cam1/h264", - "/cam1/h264/multicast", - "/cam1/mjpeg", - "/cam1/mpeg4", - "/camera.stm", - "/ch0", - "/ch001.sdp", - "/ch0_unicast_firststream", - "/ch0_unicast_secondstream", - "/channel1", - "/h264", - "/h264/media.amp", - "/image.mpg", - "/img/media.sav", - "/img/video.asf", - "/img/video.sav", - "/ioImage/1", - "/ipcam.sdp", - "/ipcam_h264.sdp", - "/live.sdp", - "/live/h264", - "/live/mpeg4", - "/live_mpeg4.sdp", - "/livestream", - "/livestream/", - "/media/media.amp", - "/media/video1", - "/mjpeg/media.smp", - "/mp4", - "/mpeg4", - "/mpeg4/1/media.amp", - "/mpeg4/media.amp", - "/mpeg4/media.smp", - "/mpeg4unicast", - "/mpg4/rtsp.amp", - "/multicaststream", - "/now.mp4", - "/nph-h264.cgi", - "/nphMpeg4/g726-640x", - "/nphMpeg4/g726-640x480", - "/nphMpeg4/nil-320x240", - "/play1.sdp", - "/play2.sdp", - "/rtpvideo1.sdp", - "/rtsp_tunnel", - "/rtsph264", - "/stream1", - "/user.pin.mp2", - "/user_defined", - "/video", - "/video.3gp", - "/video.mp4", - "/video1", - "/video1+audio1", - "/vis", - "/wfov" - ] -} diff --git a/test/docker/gen_cameras.sh b/test/docker/gen_cameras.sh deleted file mode 100755 index 11f5edc..0000000 --- a/test/docker/gen_cameras.sh +++ /dev/null @@ -1,111 +0,0 @@ -#!/bin/bash - -ports=('8554' '8554' '8554' '8554' '8554' '8554') -users=('admin' 'root' 'ubnt' 'Admin' 'supervisor' '') -passwords=('admin' 'root' '12345' 'ubnt' 'password' '') -routes=('cam0_0' 'live.sdp' 'ch001.sdp' 'cam' 'invalid' 'live_mpeg4.sdp') -cams_name_pattern="fake_camera_" - -# json generation variable only -json="[\n" -first=true -# $1 = adress, $2 = port, $3 = path, $4 = usernam $5 = password, $6 = valid -function make_json { - # Get all data about the container, this will return three lines - # One empty that we ignore - # the two other ones with the IP of our container - # We take the second one using sed and cut to get only the IPAddress - address="$(docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' $CID)" - if [ "$first" = true ] ; then first=false - else json="$json,\n"; fi - json="$json{" - json="$json\"address\":\"$address\"," - json="$json\"port\":$2," - json="$json\"route\":\"$3\"," - json="$json\"username\":\"$4\"," - json="$json\"password\":\"$5\"," - json="$json\"valid\":$6" - json="$json}" -} - -# $1 = configuration template path -function generate_conf { - echo "generate configuration" - sed s#__CAMERAS__#$json#g $1 > cameradartest.conf.json -} - -# $1 = numbers of cameras to generate -function start { - # Seed random generator - RANDOM=$(date +%s) - - # start cameras - for (( i=1; i<=$1; i++ )); do - name="$cams_name_pattern$i" - # random conf - conf_idx=$((RANDOM % ${#ports[@]})) - - # get conf variables - port=${ports[$conf_idx]} - user=${users[$conf_idx]} - passw=${passwords[$conf_idx]} - route=${routes[$conf_idx]} - is_valid=true - - # if conf_idx = 4 -> invalid conf - if [ "$conf_idx" == "4" ] ; then is_valid=false; fi - - CID=$(docker run -d --name "$name" fake-camera /start.sh "$port" "$user" "$passw" "$route"); - make_json "$name" "$port" "$route" "$user" "$passw" $is_valid $CID - done - - # finalize json - json="$json]" -} - -function stop { - # if no cameras containers are started just exit - camera_count="$(docker ps -a -q --filter="name=$cams_name_pattern" | wc -l)" - if [ "$camera_count" == "0" ]; then - echo "error: no cameras started"; exit 1 - fi - - echo "stopping and removing $camera_count containers" - # docker stop $(docker ps -a -q --filter="name=$cams_name_pattern") - docker rm -f $(docker ps -a -q --filter="name=$cams_name_pattern") > /dev/null -} - -# need first argument at least -if [ "$1" == "" ]; then - echo "error: invalid number of argument" - exit 1 -fi -case $1 in -"start") - # check if the argument is a number. - re='^[0-9]+$' - if ! [[ $2 =~ $re ]] ; then - echo "error: argument is not a number"; exit 1 - fi - if [[ "$3" == "" ]] ; then - echo "error: missing path to the configuration file template"; exit 1 - fi - echo "starting $2 cameras" - start $2 - generate_conf $3 - ;; -"stop") - echo "stopping all cameras tests" - stop - ;; -"help") - echo "./gen_cameras.sh start CAMS_NB - start CAMS_NB cameras" - echo " stop - stop all started cameras" - echo " help - display this help" - exit 0 - ;; -*) - echo "invalid test name" - exit 1 - ;; -esac diff --git a/test/docker/run_cameradartest.sh b/test/docker/run_cameradartest.sh deleted file mode 100755 index db3ab4b..0000000 --- a/test/docker/run_cameradartest.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/bash - -while ! mysqladmin ping -h"cameradar-database" -P3306 --silent; do - sleep 1 -done - -cat /tmp/tests/cameradartest.conf.json - -# build -go build - -cp /tmp/tests/*.xml ./ - -# run test -./cameradartest /tmp/tests/cameradartest.conf.json - -ret=$? - -echo "Tests exited with code ${ret}" - -cat *.xml - -cp *.xml /tmp/tests/ - -exit $ret diff --git a/test/docker/run_ces.sh b/test/docker/run_ces.sh deleted file mode 100755 index 9d05b8c..0000000 --- a/test/docker/run_ces.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/bash - -port=$1 -user=$2 -passw=$3 -route=$4 -url="" - -# need first argument at least -if [ "$2" == "" ]; then - url="rtsp://:$port/$route" -else - url="rtsp://$user:$passw@:$port/$route" -fi - -if [ "$2" == "" && "$3" == "" ]; then - ./camera_emulation_server -r $4 -else - ./camera_emulation_server -u $2 -p $3 -r $4 -fi - -echo "Stream started on ${url}" diff --git a/test/src/configuration.go b/test/src/configuration.go deleted file mode 100644 index e6688e9..0000000 --- a/test/src/configuration.go +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2016 Etix Labs -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "encoding/json" - "fmt" - "os" -) - -func (t *Tester) parseConfig() bool { - confPath := "conf/cameratest.conf.json" - av := len(os.Args) - if av > 1 { - confPath = os.Args[1] - } - - // Load config - fmt.Printf("Loading Tester configuration file: %s ... ", confPath) - configFile, err := os.Open(confPath) - if err != nil { - fmt.Printf("\nCan't open Tester configuration file: %s\n", err) - return false - } - dec := json.NewDecoder(configFile) - if err = dec.Decode(&t); err != nil { - fmt.Printf("\nUnable to deserialize Tester configuration file: %s\n", err) - return false - } - fmt.Println("Tester configuration file successfully loaded") - - return true -} diff --git a/test/src/db.go b/test/src/db.go deleted file mode 100644 index ab828fd..0000000 --- a/test/src/db.go +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2016 Etix Labs -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "database/sql" - "fmt" - "strconv" - - _ "github.com/go-sql-driver/mysql" -) - -func (t *Tester) dropDB() bool { - dsn := t.ServiceConf.DbUser + ":" + t.ServiceConf.DbPassword + "@" + "tcp(" + t.ServiceConf.DbHost + ":" + strconv.Itoa(t.ServiceConf.DbPort) + ")/" + t.ServiceConf.DbName + "?charset=utf8" - - db, err := sql.Open("mysql", dsn) - if err != nil { - fmt.Println(err) - } - - defer db.Close() - - q := "DROP DATABASE " + t.ServiceConf.DbName + ";" - _, err = db.Exec(q) - if err != nil { - fmt.Println(err) - } - - fmt.Println("------ Dropped Cameradar Database -------") - return true -} diff --git a/test/src/logReader.go b/test/src/logReader.go deleted file mode 100644 index 82717fa..0000000 --- a/test/src/logReader.go +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2016 Etix Labs -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "bufio" - "fmt" - "io" -) - -// Launch it via goroutine -// Start read log of service -func readLog(service *Service, reader io.ReadCloser) { - scanner := bufio.NewScanner(reader) - - for scanner.Scan() { - str := scanner.Text() - if service.Config.Console { - fmt.Printf("[%s] %s\n", service.Config.Path, str) - } - fmt.Printf("%s\n", str) - service.Mutex.Lock() - service.Logs = append(service.Logs, str) - service.Mutex.Unlock() - } - - err := scanner.Err() - if err != nil { - fmt.Printf("[%s] Service failed: %s\n", service.Config.Path, err) - } - - fmt.Printf("Logger of service: [%s] stopped\n", service.Config.Path) - service.Active = false -} diff --git a/test/src/main.go b/test/src/main.go deleted file mode 100644 index 3cb6a0d..0000000 --- a/test/src/main.go +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2016 Etix Labs -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "fmt" - "os" -) - -func main() { - Tester := new(Tester) - defer Tester.Stop() - - // Parse conf (streams should already be launched by Jenkins) - fmt.Println("--- Initializing Cameradar Test Tool ... ---") - if !Tester.Init() { - fmt.Println("-> Cameradar Test Tool initialization FAILED") - return - } - - // Run tests - if !Tester.Run() { - fmt.Println("-> Cameradar Test Tool FAILED") - } - - // Write results - fmt.Println("--- Writing results... ---") - if !Tester.WriteResults(*(Tester.Result), Tester.Output) { - fmt.Println("-> Write results FAILED") - os.Exit(1) - } - - fmt.Println("--- Writing results done ---") - os.Exit(0) -} diff --git a/test/src/result.go b/test/src/result.go deleted file mode 100644 index 1215ee6..0000000 --- a/test/src/result.go +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2016 Etix Labs -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "encoding/json" - "errors" - "fmt" - "os" -) - -// Result contains the data of a Cameradar result, plus an error field in order to add error messages to the JUnit report -type Result struct { - Address string `json:"address"` - IDsFound bool `json:"ids_found"` - PathFound bool `json:"path_found"` - Password string `json:"password"` - Port int `json:"port"` - Route string `json:"route"` - ServiceName string `json:"service_name"` - Protocol string `json:"protocol"` - State string `json:"state"` - Username string `json:"username"` - Valid bool `json:"valid"` - Thumb string `json:"thumbnail_path"` - err error // in case of a fail, add a message -} - -// Launch it via goroutine -// Start read log of service -func getResult(test *[]Result, resultPath string) bool { - // Load config - resultFile, err := os.Open(resultPath) - if err != nil { - fmt.Printf("\nCan't open result file: %s\n", err) - return false - } - - dec := json.NewDecoder(resultFile) - if err = dec.Decode(&test); err != nil { - fmt.Printf("\nUnable to deserialize result file: %s\n", err) - return false - } - - return true -} - -func isValid(e *Result, r Result) bool { - if e.Username != r.Username { - e.err = errors.New(e.Address + " had a different username than " + r.Username) - return false - } - if e.Password != r.Password { - e.err = errors.New(e.Address + " had a different password than " + r.Password) - return false - } - if e.Port != r.Port { - e.err = errors.New(e.Address + " had a different port than expected") - return false - } - if e.Valid != r.Valid { - e.err = errors.New(e.Address + " had a different validity than expected") - return false - } - fmt.Println(e.Address + "seems valid.") - return true -} - -// Extend takes a slice of Results and adds a new element to it -func Extend(slice []Result, element Result) []Result { - n := len(slice) - - if n == cap(slice) { - // Slice is full; must grow. - // We double its size and add 1, so if the size is zero we still grow. - newSlice := make([]Result, len(slice), 2*len(slice)+1) - copy(newSlice, slice) - slice = newSlice - } - - slice = slice[0 : n+1] - slice[n] = element - - return slice -} diff --git a/test/src/service.go b/test/src/service.go deleted file mode 100644 index a250d78..0000000 --- a/test/src/service.go +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright 2016 Etix Labs -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "fmt" - "os/exec" - "strings" - "sync" -) - -// ServiceConfig contains the configuration variables for the service structure -type ServiceConfig struct { - Path string `json:"path"` - Args string `json:"args"` - Ports string `json:"ports"` - IdsPath string `json:"ids_path"` - RoutesPath string `json:"routes_path"` - ThumbPath string `json:"thumb_path"` - DbHost string `json:"db_host"` - DbPort int `json:"db_port"` - DbUser string `json:"db_user"` - DbPassword string `json:"db_password"` - DbName string `json:"db_name"` - Console bool `json:"console"` -} - -// Service allows to run a command and to access its logs asynchronously -type Service struct { - Config ServiceConfig // Configuration variables - Logs []string // Contains the executer's logs - Active bool // Based on io.ReadCloser status - Mutex sync.Mutex // Used to append to the logs safely - cmd *exec.Cmd // Pointer to the executer -} - -func startService(service *Service, config ServiceConfig) bool { - // Launch service - service.Config = config - args := strings.Fields(service.Config.Args) - service.cmd = exec.Command(service.Config.Path, args...) - - handler, err := service.cmd.StdoutPipe() - if err != nil { - fmt.Println(err) - return false - } - errHandler, err := service.cmd.StderrPipe() - if err != nil { - fmt.Println(err) - return false - } - // Launch - err = service.cmd.Start() - if err != nil { - fmt.Println(err) - return false - } - - fmt.Printf("Service: [%s] started\n", service.Config.Path) - service.Active = true - - // Read service logs and update service status - // Set pipes - go readLog(service, handler) - go readLog(service, errHandler) - - return true -} - -// Stop only specified service instance -func stopService(service *Service) { - service.cmd.Process.Kill() -} - -// Kill all instances of specified service -func killService(service *Service) { - // Sending SIGTERM - fmt.Printf("Executing: killall %s\n", service.Config.Path) - cmd := exec.Command("killall", service.Config.Path) - err := cmd.Run() - if err != nil { - fmt.Println(err) - } - - sigAbort := []string{service.Config.Path, "-s", "SIGABRT"} - fmt.Printf("Executing: killall %s -s SIGABRT\n", service.Config.Path) - cmd = exec.Command("killall", sigAbort...) - err = cmd.Run() - if err != nil { - fmt.Println(err) - } -} diff --git a/test/src/testCase.go b/test/src/testCase.go deleted file mode 100644 index 9930170..0000000 --- a/test/src/testCase.go +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2016 Etix Labs -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "errors" - "fmt" - "sync" - "time" -) - -// Test represents a test launched with Cameradar -type Test struct { - expected []Result // Contains the expected results - result []Result // Contains the results that have been validated - time time.Duration // Contains the runtime duration -} - -func removeResult(expected []Result, index int) []Result { - if len(expected) > 1 { - return append(expected[:index], expected[index+1:]...) - } - return []Result{} -} - -// Invoke the test -// Wrap results in a TestResult object -func (t *Tester) invokeTestCase(testCase *Test, wg *sync.WaitGroup) { - startTime := time.Now() - t.runTestCase(testCase) - testCase.time = time.Since(startTime) - fmt.Printf("Test OK in %.6fs\n", testCase.time.Seconds()) - wg.Done() -} - -// Checks all valid results that are supposed to match -// Adds them to the valid results and leave the failed -// ones in the expected slice -// -// Then, if the result did not match the expected but it was supposed to fail -// Add it to the valid results and remove it from the expected slice -func (t *Tester) runTestCase(test *Test) { - startService(&t.Cameradar, t.ServiceConf) - for t.Cameradar.Active { - time.Sleep(25 * time.Millisecond) - } - - var validResults []Result - var invalidResults []Result - if getResult(&test.result, "/tmp/shared/result.json") { - for _, r := range test.result { - r.Valid = true - - for index, e := range test.expected { - fmt.Println("Result : ", r) - fmt.Println("Expected test : ", e) - - if e.Address == r.Address && isValid(&e, r) { - fmt.Println("The result of ", r.Address, " is valid.") - validResults = Extend(validResults, r) - test.expected = removeResult(test.expected, index) - break - } - } - } - - for _, e := range test.expected { - if !e.Valid { - fmt.Println("The result of", e.Address, "successfully failed.") - validResults = Extend(validResults, e) - } else { - if e.err == nil { - e.err = errors.New("The camera with the address " + e.Address + " was not found by cameradar") - } - invalidResults = Extend(invalidResults, e) - fmt.Println("Should have been valid but was not found : ", e.Address) - } - } - test.result = validResults - test.expected = invalidResults - } else { - test.expected = nil - test.result = nil - } -} diff --git a/test/src/tester.go b/test/src/tester.go deleted file mode 100644 index 2072dab..0000000 --- a/test/src/tester.go +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2016 Etix Labs -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "fmt" - "sync" -) - -// Tester is the structure that will manage the whole testing -type Tester struct { - ServiceConf ServiceConfig `json:"cameradar"` - Output string `json:"output"` - Tests []Result `json:"tests"` - - Cameradar Service - Result *Test -} - -// Init gets the testing configuration and makes sure that no other Cameradar service is running at the moment -func (t *Tester) Init() bool { - fmt.Println("- Parsing") - if !t.parseConfig() { - return false - } - - fmt.Println("- Cleaning content") - killService(&t.Cameradar) - - return true -} - -// Run launches the tests that have been set up by the init method -func (t *Tester) Run() bool { - var wg sync.WaitGroup - - fmt.Println("\n- Launching all tests") - var newTest = new(Test) - newTest.expected = t.Tests - - t.dropDB() - wg.Add(1) - go t.invokeTestCase(newTest, &wg) - t.Result = newTest - - wg.Wait() - fmt.Println("All tests completed") - return true -} - -// Stop kills the service launched by the tester -func (t *Tester) Stop() bool { - killService(&t.Cameradar) - return true -} diff --git a/test/src/writeResult.go b/test/src/writeResult.go deleted file mode 100644 index e15ef4c..0000000 --- a/test/src/writeResult.go +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright 2016 Etix Labs -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "bytes" - "encoding/xml" - "errors" - "fmt" - "io" - "io/ioutil" - "os" -) - -// JUnitTestSuites is a collection of JUnit test suites. -type JUnitTestSuites struct { - XMLName xml.Name `xml:"testsuites"` - TestSuites []JUnitTestSuite `xml:"testsuite"` -} - -// JUnitTestSuite is a single JUnit test suite which may contain many -// testcases. -type JUnitTestSuite struct { - XMLName xml.Name `xml:"testsuite"` - Tests int `xml:"tests,attr"` - Failures int `xml:"failures,attr"` - Time string `xml:"time,attr"` - TestCases []JUnitTestCase `xml:"testcase"` -} - -// JUnitTestCase is a single test case with its result. -type JUnitTestCase struct { - XMLName xml.Name `xml:"testcase"` - Message string `xml:"message,attr"` - Time string `xml:"time,attr"` - Failure *JUnitFailure `xml:"failure,omitempty"` -} - -// JUnitFailure contains data related to a failed test. -type JUnitFailure struct { - XMLName xml.Name `xml:"failure"` - Message string `xml:"message,attr"` - Type string `xml:"type,attr"` - Contents string `xml:",chardata"` -} - -// WriteResults will output the results in the standard output as well as concatenate them in an XML JUnit report -func (t *Tester) WriteResults(result Test, output string) bool { - file, err := os.OpenFile(output, os.O_RDONLY|os.O_CREATE, 0644) - if err != nil { - fmt.Printf("Error opening XML: %s\n", err) - return false - } - defer file.Close() - - err = t.writeJUnitReportXML(result, file, output) - if err != nil { - fmt.Printf("The tests were unsuccessful: %s\n", err) - return false - } - - fmt.Printf("-> JUnit XML report written: %s\n", output) - return true -} - -// Write tests results under JUnit format on w -func (t *Tester) writeJUnitReportXML(result Test, rw io.ReadWriter, output string) error { - if result.expected == nil && result.result == nil { - return errors.New("test results could not be deserialized") - } - - suites := JUnitTestSuites{} - - buf, err := ioutil.ReadFile(output) - - dec := xml.NewDecoder(bytes.NewBufferString(string(buf))) - err = dec.Decode(&suites) - if err != nil { - fmt.Printf("\nUnable to deserialize %s file: %s\n", output, err) - } - - ts := JUnitTestSuite{ - Tests: len(result.result) + len(result.expected), - Failures: len(result.expected), - Time: fmt.Sprintf("%.6f", result.time.Seconds()), - TestCases: []JUnitTestCase{}, - } - - for _, r := range result.result { - testCase := JUnitTestCase{ - Time: fmt.Sprintf("%.6f", result.time.Seconds()), - Failure: nil, - } - testCase.Message = "The stream " + r.Address + " had the expected result" - ts.TestCases = append(ts.TestCases, testCase) - } - - for _, e := range result.expected { - testCase := JUnitTestCase{ - Time: fmt.Sprintf("%.6f", result.time.Seconds()), - Failure: nil, - } - - if e.err != nil { - testCase.Failure = &JUnitFailure{ - Message: e.err.Error(), - Type: "", - } - } - ts.TestCases = append(ts.TestCases, testCase) - } - - successCount := 0 - failureCount := 0 - for _, test := range ts.TestCases { - if test.Failure != nil { - failureCount++ - } else { - successCount++ - } - } - - fmt.Println("--- Test summary ---") - if successCount > 0 { - fmt.Printf("Results: %d/%d (%d%%)\n", successCount, successCount+failureCount, successCount*100/(successCount+failureCount)) - fmt.Printf("Time: %.6fs\n", result.time.Seconds()) - } else { - fmt.Printf("No test in success\n") - } - - suites.TestSuites = append(suites.TestSuites, ts) - bytes, err := xml.MarshalIndent(suites, "", "\t") - if err != nil { - return err - } - - w, err := os.OpenFile(output, os.O_WRONLY|os.O_TRUNC, 0644) - if err != nil { - return err - } - - writer := io.Writer(w) - writer.Write(bytes) - - if failureCount > 0 { - return errors.New("some cameras were not successfully accessed") - } - return nil -} diff --git a/test/test.sh b/test/test.sh deleted file mode 100755 index d2052ae..0000000 --- a/test/test.sh +++ /dev/null @@ -1,72 +0,0 @@ -#!/bin/bash - -# check if a debug package exist in the current folder -if ! ls ./cameradar_*_Debug_Linux.tar.gz 1> /dev/null 2>&1; then - (echo "no debug package in the current folder"; exit 137) - exit 137 -fi - -cams_name_pattern="fake_camera_" -cmd="" - -function make_docker_command { - cmd="docker run --rm" - - # start cameras - for (( i=1; i<=$1; i++ )); do - name="$cams_name_pattern$i" - cmd="$cmd --link=\"$name\"" - done - - # add mysql link - cmd="$cmd --link=\"cameradar-database\"" - # add cameradar sources - cmd="$cmd -v \"$(pwd)/src:/go/src/cameradartest\"" - # add cameradar testing volume - cmd="$cmd -v \"$(pwd)/:/tmp/tests\"" - # add cameradar shared volume - cmd="$cmd -v \"$(pwd)/:/tmp/shared\"" - # add container name - cmd="$cmd cameradartest" -} - -function start_test { - # Generate all cameras - ./docker/gen_cameras.sh start $1 ./docker/cameratest.conf.tmpl.json - - # Prepare docker command - make_docker_command $1 - - # Launch docker command - eval $cmd - - # Get its return - ret=$? - - # Stop all camera containers - ./docker/gen_cameras.sh stop - - return $ret -} - -echo "building docker images" - -# building fake-camera container -docker build --no-cache -f Dockerfile-camera -t fake-camera . - -# building cameradartest image -docker build --no-cache -t cameradartest . - -# getting mysql -echo "starting mysql" -docker pull mysql:5.7 -docker run --name cameradar-database -e MYSQL_DATABASE=cmrdr -e MYSQL_ROOT_PASSWORD=root -d mysql:5.7 - -start_test 5 -ret=$? -echo "Tests returned ${ret}" - -# stop mysql -echo "stopping mysql" -docker rm -f cameradar-database -exit $ret diff --git a/version.h.in b/version.h.in deleted file mode 100644 index deecad2..0000000 --- a/version.h.in +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2016 Etix Labs -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef __CAMERADAR_H__201605202152__ -#define __CAMERADAR_H__201605202152__ - -// the configured options and settings for Tutorial -#define CAMERADAR_VERSION "@cameradar_VERSION@" -#define CAMERADAR_VERSION_MAJOR @cameradar_VERSION_MAJOR@ -#define CAMERADAR_VERSION_MINOR @cameradar_VERSION_MINOR@ -#define CAMERADAR_VERSION_PATCH @cameradar_VERSION_PATCH@ -#define CAMERADAR_VERSION_GIT_SHA1 "@CAMERADAR_VERSION_SHA1@" -#define CAMERADAR_VERSION_BUILD "@CAMERADAR_VERSION_BUILD@" - -#endif // __CAMERADAR_H__201605202152__