<commit_before>/* Rapicorn
 * Copyright (C) 2005 Tim Janik
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * A copy of the GNU Lesser General Public License should ship along
 * with this library; if not, see http://www.gnu.org/copyleft/.
 */
#ifndef __RAPICORN_ENUMDEFS_HH__
#define __RAPICORN_ENUMDEFS_HH__

#include <rapicorn-core/rapicornutils.hh>

namespace Rapicorn {

/* --- enum/flags type descriptions --- */
struct EnumClass {
  struct Value {
    const int64             value;
    const char       *const value_name;
    const uint              name_length;
  };
  virtual            ~EnumClass         () {}
  virtual void        list_values       (uint &n_values, const Value* &values) const = 0;
  virtual const char* enum_name         () const = 0;
  virtual bool        flag_combinable   () const = 0;
  virtual int64       constrain         (int64 value) const = 0;
  bool                match_partial     (const char *value_name1, const char *partial_value_name) const;
  bool                match             (const char *value_name1, const char *value_name2) const;
  const Value*        find_first        (int64 value) const;
  const Value*        find_first        (const String &value_name) const;
  int64               parse             (const char *value_string, String *error = NULL) const;
  String              string            (int64 value) const;
};
template<typename EnumType> EnumType inline enum_type_constrain (EnumType value) { return value; }
template<typename EType>
struct EnumType : public virtual EnumClass {
  typedef EType Type;
  virtual void        list_values       (uint &c_n_values, const Value* &c_values) const { c_n_values = n_values, c_values = values; }
  virtual const char* enum_name         () const { return ename; }
  virtual bool        flag_combinable   () const { return false; }
  virtual int64       constrain         (int64 value) const { return enum_type_constrain<EType> (EType (value)); }
private:
  static const uint         n_values;
  static const Value *const values;
  static const char        *ename;
};
template<typename EType>
struct FlagsType : public virtual EnumClass {
  typedef EType Type;
  virtual void        list_values       (uint &c_n_values, const Value* &c_values) const { c_n_values = n_values, c_values = values; }
  virtual const char* enum_name         () const { return ename; }
  virtual bool        flag_combinable   () const { return true; }
  virtual int64       constrain         (int64 value) const { return enum_type_constrain<EType> (EType (value)); }
private:
  static const uint         n_values;
  static const Value *const values;
  static const char        *ename;
};

/* --- enums --- */
typedef enum {
  ADJUSTMENT_SOURCE_NONE = 0,
  ADJUSTMENT_SOURCE_ANCESTRY_HORIZONTAL,
  ADJUSTMENT_SOURCE_ANCESTRY_VERTICAL,
  ADJUSTMENT_SOURCE_ANCESTRY_VALUE
} AdjustmentSourceType;
typedef EnumType<AdjustmentSourceType> EnumTypeAdjustmentSourceType;

typedef enum {
  ALIGN_LEFT = 1,
  ALIGN_CENTER,
  ALIGN_RIGHT,
} AlignType;
typedef EnumType<AlignType> EnumTypeAlignType;

typedef enum {
  ANCHOR_NONE,
  ANCHOR_CENTER,
  ANCHOR_EAST,
  ANCHOR_NORTH_EAST,
  ANCHOR_NORTH,
  ANCHOR_NORTH_WEST,
  ANCHOR_WEST,
  ANCHOR_SOUTH_WEST,
  ANCHOR_SOUTH,
  ANCHOR_SOUTH_EAST,
} AnchorType;
typedef EnumType<AnchorType> EnumTypeAnchorType;

typedef enum {
  CLICK_ON_PRESS        = 1,
  CLICK_ON_RELEASE,
  CLICK_SLOW_REPEAT,
  CLICK_FAST_REPEAT,
  CLICK_KEY_REPEAT,
} ClickType;
typedef EnumType<ClickType> EnumTypeClickType;

typedef enum {
  COLOR_NONE,
  COLOR_FOREGROUND,
  COLOR_BACKGROUND,
  COLOR_BACKGROUND_EVEN,
  COLOR_BACKGROUND_ODD,
  COLOR_DARK,
  COLOR_DARK_SHADOW,
  COLOR_DARK_GLINT,
  COLOR_LIGHT,
  COLOR_LIGHT_SHADOW,
  COLOR_LIGHT_GLINT,
  COLOR_FOCUS,
  COLOR_BLACK,
  COLOR_WHITE,
  COLOR_RED,
  COLOR_YELLOW,
  COLOR_GREEN,
  COLOR_CYAN,
  COLOR_BLUE,
  COLOR_MAGENTA,
} ColorType;
typedef EnumType<ColorType> EnumTypeColorType;

typedef enum {
  COLOR_INHERIT,
  COLOR_NORMAL,
  COLOR_SELECTED,
  COLOR_BASE,
} ColorSchemeType;
typedef EnumType<ColorSchemeType> EnumTypeColorSchemeType;

typedef enum {
  DIR_NONE,
  DIR_RIGHT,
  DIR_UP,
  DIR_LEFT,
  DIR_DOWN,
} DirType;
typedef EnumType<DirType> EnumTypeDirType;

typedef enum {
  ELLIPSIZE_START = 1,
  ELLIPSIZE_MIDDLE,
  ELLIPSIZE_END
} EllipsizeType;
typedef EnumType<EllipsizeType> EnumTypeEllipsizeType;

typedef enum {
  FOCUS_NEXT    = 1,
  FOCUS_PREV,
  FOCUS_RIGHT,
  FOCUS_UP,
  FOCUS_LEFT,
  FOCUS_DOWN
} FocusDirType;
typedef EnumType<FocusDirType> EnumTypeFocusDirType;

typedef enum {
  FRAME_NONE,
  FRAME_BACKGROUND,
  FRAME_IN,
  FRAME_OUT,
  FRAME_ETCHED_IN,
  FRAME_ETCHED_OUT,
  FRAME_FOCUS,
  FRAME_ALERT_FOCUS,
} FrameType;
typedef EnumType<FrameType> EnumTypeFrameType;

typedef enum {
  LIGHTING_NONE,
  LIGHTING_UPPER_LEFT,
  LIGHTING_UPPER_RIGHT,
  LIGHTING_LOWER_LEFT,
  LIGHTING_LOWER_RIGHT,
  LIGHTING_CENTER,
  LIGHTING_DIFFUSE,
  LIGHTING_DARK_UPPER_LEFT   = 0x80 | LIGHTING_UPPER_LEFT,
  LIGHTING_DARK_UPPER_RIGHT  = 0x80 | LIGHTING_UPPER_RIGHT,
  LIGHTING_DARK_LOWER_LEFT   = 0x80 | LIGHTING_LOWER_LEFT,
  LIGHTING_DARK_LOWER_RIGHT  = 0x80 | LIGHTING_LOWER_RIGHT,
  LIGHTING_DARK_CENTER       = 0x80 | LIGHTING_CENTER,
  LIGHTING_DARK_DIFFUSE      = 0x80 | LIGHTING_DIFFUSE,
} LightingType;
static const LightingType LIGHTING_DARK_FLAG = LightingType (0x80);
typedef EnumType<LightingType> EnumTypeLightingType;
inline LightingType  operator&  (LightingType  s1, LightingType s2) { return LightingType (s1 & (uint64) s2); }
inline LightingType& operator&= (LightingType &s1, LightingType s2) { s1 = s1 & s2; return s1; }
inline LightingType  operator|  (LightingType  s1, LightingType s2) { return LightingType (s1 | (uint64) s2); }
inline LightingType& operator|= (LightingType &s1, LightingType s2) { s1 = s1 | s2; return s1; }

typedef enum {
  SIZE_POLICY_NORMAL            = 0,
  SIZE_POLICY_WIDTH_FROM_HEIGHT,
  SIZE_POLICY_HEIGHT_FROM_WIDTH,
} SizePolicyType;
typedef EnumType<SizePolicyType> EnumTypeSizePolicyType;

typedef enum {
  STATE_INSENSITIVE     = 1 << 0,
  STATE_PRELIGHT        = 1 << 1,
  STATE_IMPRESSED       = 1 << 2,
  STATE_FOCUS           = 1 << 3,
  STATE_DEFAULT         = 1 << 4,
} StateType;
static const StateType STATE_NORMAL = StateType (0);
static const StateType STATE_MASK = StateType (0x1f);
typedef FlagsType<StateType> FlagsTypeStateType;
inline StateType  operator&  (StateType  s1, StateType s2) { return StateType (s1 & (uint64) s2); }
inline StateType& operator&= (StateType &s1, StateType s2) { s1 = s1 & s2; return s1; }
inline StateType  operator|  (StateType  s1, StateType s2) { return StateType (s1 | (uint64) s2); }
inline StateType& operator|= (StateType &s1, StateType s2) { s1 = s1 | s2; return s1; }

typedef enum /*<enum>*/
{
  NUM            = 'i',
  REAL           = 'f',
  STRING         = 's',
  ARRAY          = 'a',
  OBJECT         = 'c',
  INTERFACE      = OBJECT,
  CHOICE         = ('C' * 256) + STRING,
  TYPE_REFERENCE = ('T' * 256) + STRING,
  SEQUENCE       = ('Q' * 256) + ARRAY,
  RECORD         = ('R' * 256) + ARRAY,
} StorageType;
typedef EnumType<StorageType> EnumTypeStorageType;

typedef enum {
  TEXT_MODE_WRAPPED = 1,
  TEXT_MODE_ELLIPSIZED,
  TEXT_MODE_SINGLE_LINE,
} TextMode;
typedef EnumType<TextMode> EnumTypeTextMode;

typedef enum {
  /* main window types */
  WINDOW_TYPE_NORMAL  = 0,
  WINDOW_TYPE_DESKTOP,          /* desktop background */
  WINDOW_TYPE_DOCK,             /* dock or panel */
  WINDOW_TYPE_TOOLBAR,          /* torn-off toolbar */
  WINDOW_TYPE_MENU,             /* torn-off menu */
  WINDOW_TYPE_UTILITY,          /* palette or toolbox */
  WINDOW_TYPE_SPLASH,           /* startup/splash screen */
  WINDOW_TYPE_DIALOG,           /* dialog window, usually transient */
  WINDOW_TYPE_DROPDOWN_MENU,    /* menu, opened from menubar */
  WINDOW_TYPE_POPUP_MENU,       /* menu, opened as context menu */
  WINDOW_TYPE_TOOLTIP,          /* transient context info window */
  WINDOW_TYPE_NOTIFICATION,     /* transient info window (e.g. info bubble) */
  WINDOW_TYPE_COMBO,            /* combo box menu or list window */
  WINDOW_TYPE_DND,              /* window being dragged in a DND operation */
} WindowType;
typedef EnumType<WindowType> EnumTypeWindowType;

} // Rapicorn

#endif  /* __RAPICORN_ENUMDEFS_HH__ */
<commit_msg>enumdefs.hh: adapt type code to latest Plic version<commit_after>/* Rapicorn
 * Copyright (C) 2005 Tim Janik
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * A copy of the GNU Lesser General Public License should ship along
 * with this library; if not, see http://www.gnu.org/copyleft/.
 */
#ifndef __RAPICORN_ENUMDEFS_HH__
#define __RAPICORN_ENUMDEFS_HH__

#include <rapicorn-core/rapicornutils.hh>

namespace Rapicorn {

/* --- enum/flags type descriptions --- */
struct EnumClass {
  struct Value {
    const int64             value;
    const char       *const value_name;
    const uint              name_length;
  };
  virtual            ~EnumClass         () {}
  virtual void        list_values       (uint &n_values, const Value* &values) const = 0;
  virtual const char* enum_name         () const = 0;
  virtual bool        flag_combinable   () const = 0;
  virtual int64       constrain         (int64 value) const = 0;
  bool                match_partial     (const char *value_name1, const char *partial_value_name) const;
  bool                match             (const char *value_name1, const char *value_name2) const;
  const Value*        find_first        (int64 value) const;
  const Value*        find_first        (const String &value_name) const;
  int64               parse             (const char *value_string, String *error = NULL) const;
  String              string            (int64 value) const;
};
template<typename EnumType> EnumType inline enum_type_constrain (EnumType value) { return value; }
template<typename EType>
struct EnumType : public virtual EnumClass {
  typedef EType Type;
  virtual void        list_values       (uint &c_n_values, const Value* &c_values) const { c_n_values = n_values, c_values = values; }
  virtual const char* enum_name         () const { return ename; }
  virtual bool        flag_combinable   () const { return false; }
  virtual int64       constrain         (int64 value) const { return enum_type_constrain<EType> (EType (value)); }
private:
  static const uint         n_values;
  static const Value *const values;
  static const char        *ename;
};
template<typename EType>
struct FlagsType : public virtual EnumClass {
  typedef EType Type;
  virtual void        list_values       (uint &c_n_values, const Value* &c_values) const { c_n_values = n_values, c_values = values; }
  virtual const char* enum_name         () const { return ename; }
  virtual bool        flag_combinable   () const { return true; }
  virtual int64       constrain         (int64 value) const { return enum_type_constrain<EType> (EType (value)); }
private:
  static const uint         n_values;
  static const Value *const values;
  static const char        *ename;
};

/* --- enums --- */
typedef enum {
  ADJUSTMENT_SOURCE_NONE = 0,
  ADJUSTMENT_SOURCE_ANCESTRY_HORIZONTAL,
  ADJUSTMENT_SOURCE_ANCESTRY_VERTICAL,
  ADJUSTMENT_SOURCE_ANCESTRY_VALUE
} AdjustmentSourceType;
typedef EnumType<AdjustmentSourceType> EnumTypeAdjustmentSourceType;

typedef enum {
  ALIGN_LEFT = 1,
  ALIGN_CENTER,
  ALIGN_RIGHT,
} AlignType;
typedef EnumType<AlignType> EnumTypeAlignType;

typedef enum {
  ANCHOR_NONE,
  ANCHOR_CENTER,
  ANCHOR_EAST,
  ANCHOR_NORTH_EAST,
  ANCHOR_NORTH,
  ANCHOR_NORTH_WEST,
  ANCHOR_WEST,
  ANCHOR_SOUTH_WEST,
  ANCHOR_SOUTH,
  ANCHOR_SOUTH_EAST,
} AnchorType;
typedef EnumType<AnchorType> EnumTypeAnchorType;

typedef enum {
  CLICK_ON_PRESS        = 1,
  CLICK_ON_RELEASE,
  CLICK_SLOW_REPEAT,
  CLICK_FAST_REPEAT,
  CLICK_KEY_REPEAT,
} ClickType;
typedef EnumType<ClickType> EnumTypeClickType;

typedef enum {
  COLOR_NONE,
  COLOR_FOREGROUND,
  COLOR_BACKGROUND,
  COLOR_BACKGROUND_EVEN,
  COLOR_BACKGROUND_ODD,
  COLOR_DARK,
  COLOR_DARK_SHADOW,
  COLOR_DARK_GLINT,
  COLOR_LIGHT,
  COLOR_LIGHT_SHADOW,
  COLOR_LIGHT_GLINT,
  COLOR_FOCUS,
  COLOR_BLACK,
  COLOR_WHITE,
  COLOR_RED,
  COLOR_YELLOW,
  COLOR_GREEN,
  COLOR_CYAN,
  COLOR_BLUE,
  COLOR_MAGENTA,
} ColorType;
typedef EnumType<ColorType> EnumTypeColorType;

typedef enum {
  COLOR_INHERIT,
  COLOR_NORMAL,
  COLOR_SELECTED,
  COLOR_BASE,
} ColorSchemeType;
typedef EnumType<ColorSchemeType> EnumTypeColorSchemeType;

typedef enum {
  DIR_NONE,
  DIR_RIGHT,
  DIR_UP,
  DIR_LEFT,
  DIR_DOWN,
} DirType;
typedef EnumType<DirType> EnumTypeDirType;

typedef enum {
  ELLIPSIZE_START = 1,
  ELLIPSIZE_MIDDLE,
  ELLIPSIZE_END
} EllipsizeType;
typedef EnumType<EllipsizeType> EnumTypeEllipsizeType;

typedef enum {
  FOCUS_NEXT    = 1,
  FOCUS_PREV,
  FOCUS_RIGHT,
  FOCUS_UP,
  FOCUS_LEFT,
  FOCUS_DOWN
} FocusDirType;
typedef EnumType<FocusDirType> EnumTypeFocusDirType;

typedef enum {
  FRAME_NONE,
  FRAME_BACKGROUND,
  FRAME_IN,
  FRAME_OUT,
  FRAME_ETCHED_IN,
  FRAME_ETCHED_OUT,
  FRAME_FOCUS,
  FRAME_ALERT_FOCUS,
} FrameType;
typedef EnumType<FrameType> EnumTypeFrameType;

typedef enum {
  LIGHTING_NONE,
  LIGHTING_UPPER_LEFT,
  LIGHTING_UPPER_RIGHT,
  LIGHTING_LOWER_LEFT,
  LIGHTING_LOWER_RIGHT,
  LIGHTING_CENTER,
  LIGHTING_DIFFUSE,
  LIGHTING_DARK_UPPER_LEFT   = 0x80 | LIGHTING_UPPER_LEFT,
  LIGHTING_DARK_UPPER_RIGHT  = 0x80 | LIGHTING_UPPER_RIGHT,
  LIGHTING_DARK_LOWER_LEFT   = 0x80 | LIGHTING_LOWER_LEFT,
  LIGHTING_DARK_LOWER_RIGHT  = 0x80 | LIGHTING_LOWER_RIGHT,
  LIGHTING_DARK_CENTER       = 0x80 | LIGHTING_CENTER,
  LIGHTING_DARK_DIFFUSE      = 0x80 | LIGHTING_DIFFUSE,
} LightingType;
static const LightingType LIGHTING_DARK_FLAG = LightingType (0x80);
typedef EnumType<LightingType> EnumTypeLightingType;
inline LightingType  operator&  (LightingType  s1, LightingType s2) { return LightingType (s1 & (uint64) s2); }
inline LightingType& operator&= (LightingType &s1, LightingType s2) { s1 = s1 & s2; return s1; }
inline LightingType  operator|  (LightingType  s1, LightingType s2) { return LightingType (s1 | (uint64) s2); }
inline LightingType& operator|= (LightingType &s1, LightingType s2) { s1 = s1 | s2; return s1; }

typedef enum {
  SIZE_POLICY_NORMAL            = 0,
  SIZE_POLICY_WIDTH_FROM_HEIGHT,
  SIZE_POLICY_HEIGHT_FROM_WIDTH,
} SizePolicyType;
typedef EnumType<SizePolicyType> EnumTypeSizePolicyType;

typedef enum {
  STATE_INSENSITIVE     = 1 << 0,
  STATE_PRELIGHT        = 1 << 1,
  STATE_IMPRESSED       = 1 << 2,
  STATE_FOCUS           = 1 << 3,
  STATE_DEFAULT         = 1 << 4,
} StateType;
static const StateType STATE_NORMAL = StateType (0);
static const StateType STATE_MASK = StateType (0x1f);
typedef FlagsType<StateType> FlagsTypeStateType;
inline StateType  operator&  (StateType  s1, StateType s2) { return StateType (s1 & (uint64) s2); }
inline StateType& operator&= (StateType &s1, StateType s2) { s1 = s1 & s2; return s1; }
inline StateType  operator|  (StateType  s1, StateType s2) { return StateType (s1 | (uint64) s2); }
inline StateType& operator|= (StateType &s1, StateType s2) { s1 = s1 | s2; return s1; }

typedef enum /*<enum>*/
{
  NUM            = 'i',
  REAL           = 'f',
  STRING         = 's',
  ARRAY          = 'a',
  OBJECT         = 'c',
  INTERFACE      = OBJECT,
  CHOICE         = ('E' * 256) + STRING,
  TYPE_REFERENCE = ('T' * 256) + STRING,
  SEQUENCE       = ('Q' * 256) + ARRAY,
  RECORD         = ('R' * 256) + ARRAY,
} StorageType;
typedef EnumType<StorageType> EnumTypeStorageType;

typedef enum {
  TEXT_MODE_WRAPPED = 1,
  TEXT_MODE_ELLIPSIZED,
  TEXT_MODE_SINGLE_LINE,
} TextMode;
typedef EnumType<TextMode> EnumTypeTextMode;

typedef enum {
  /* main window types */
  WINDOW_TYPE_NORMAL  = 0,
  WINDOW_TYPE_DESKTOP,          /* desktop background */
  WINDOW_TYPE_DOCK,             /* dock or panel */
  WINDOW_TYPE_TOOLBAR,          /* torn-off toolbar */
  WINDOW_TYPE_MENU,             /* torn-off menu */
  WINDOW_TYPE_UTILITY,          /* palette or toolbox */
  WINDOW_TYPE_SPLASH,           /* startup/splash screen */
  WINDOW_TYPE_DIALOG,           /* dialog window, usually transient */
  WINDOW_TYPE_DROPDOWN_MENU,    /* menu, opened from menubar */
  WINDOW_TYPE_POPUP_MENU,       /* menu, opened as context menu */
  WINDOW_TYPE_TOOLTIP,          /* transient context info window */
  WINDOW_TYPE_NOTIFICATION,     /* transient info window (e.g. info bubble) */
  WINDOW_TYPE_COMBO,            /* combo box menu or list window */
  WINDOW_TYPE_DND,              /* window being dragged in a DND operation */
} WindowType;
typedef EnumType<WindowType> EnumTypeWindowType;

} // Rapicorn

#endif  /* __RAPICORN_ENUMDEFS_HH__ */
<|endoftext|>


<commit_before>/*
    open source routing machine
    Copyright (C) Dennis Luxen, 2010

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU AFFERO General Public License as published by
the Free Software Foundation; either version 3 of the License, or
any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
or see http://www.gnu.org/licenses/agpl.txt.
 */

#include "Algorithms/IteratorBasedCRC32.h"
#include "Contractor/Contractor.h"
#include "Contractor/EdgeBasedGraphFactory.h"
#include "DataStructures/BinaryHeap.h"
#include "DataStructures/DeallocatingVector.h"
#include "DataStructures/NNGrid.h"
#include "DataStructures/QueryEdge.h"
#include "Util/BaseConfiguration.h"
#include "Util/GraphLoader.h"
#include "Util/InputFileUtil.h"
#include "Util/LuaUtil.h"
#include "Util/OpenMPWrapper.h"
#include "Util/StringUtil.h"
#include "typedefs.h"

#include <boost/foreach.hpp>

#include <luabind/luabind.hpp>

#include <fstream>
#include <istream>
#include <iostream>
#include <cstring>
#include <string>
#include <vector>

typedef QueryEdge::EdgeData EdgeData;
typedef DynamicGraph<EdgeData>::InputEdge InputEdge;
typedef StaticGraph<EdgeData>::InputEdge StaticEdge;
typedef BaseConfiguration ContractorConfiguration;

std::vector<NodeInfo> internalToExternalNodeMapping;
std::vector<_Restriction> inputRestrictions;
std::vector<NodeID> bollardNodes;
std::vector<NodeID> trafficLightNodes;
std::vector<ImportEdge> edgeList;

int main (int argc, char *argv[]) {
    if(argc < 3) {
        ERR("usage: " << std::endl << argv[0] << " <osrm-data> <osrm-restrictions> [<profile>]");
    }

    double startupTime = get_timestamp();
    unsigned numberOfThreads = omp_get_num_procs();
    if(testDataFile("contractor.ini")) {
        ContractorConfiguration contractorConfig("contractor.ini");
        unsigned rawNumber = stringToInt(contractorConfig.GetParameter("Threads"));
        if(rawNumber != 0 && rawNumber <= numberOfThreads)
            numberOfThreads = rawNumber;
    }
    omp_set_num_threads(numberOfThreads);

    INFO("Using restrictions from file: " << argv[2]);
    std::ifstream restrictionsInstream(argv[2], std::ios::binary);
    if(!restrictionsInstream.good()) {
        ERR("Could not access <osrm-restrictions> files");
    }
    _Restriction restriction;
    unsigned usableRestrictionsCounter(0);
    restrictionsInstream.read((char*)&usableRestrictionsCounter, sizeof(unsigned));
    inputRestrictions.resize(usableRestrictionsCounter);
    restrictionsInstream.read((char *)&(inputRestrictions[0]), usableRestrictionsCounter*sizeof(_Restriction));
    restrictionsInstream.close();

    std::ifstream in;
    in.open (argv[1], std::ifstream::in | std::ifstream::binary);
    if (!in.is_open()) {
        ERR("Cannot open " << argv[1]);
    }

    std::string nodeOut(argv[1]);		nodeOut += ".nodes";
    std::string edgeOut(argv[1]);		edgeOut += ".edges";
    std::string graphOut(argv[1]);		graphOut += ".hsgr";
    std::string ramIndexOut(argv[1]);	ramIndexOut += ".ramIndex";
    std::string fileIndexOut(argv[1]);	fileIndexOut += ".fileIndex";

    /*** Setup Scripting Environment ***/
    if(!testDataFile( (argc > 3 ? argv[3] : "profile.lua") )) {
        ERR("Need profile.lua to apply traffic signal penalty");
    }

    // Create a new lua state
    lua_State *myLuaState = luaL_newstate();

    // Connect LuaBind to this lua state
    luabind::open(myLuaState);

    //open utility libraries string library;
    luaL_openlibs(myLuaState);

    //adjust lua load path
    luaAddScriptFolderToLoadPath( myLuaState, (argc > 3 ? argv[3] : "profile.lua") );

    // Now call our function in a lua script
    INFO("Parsing speedprofile from " << (argc > 3 ? argv[3] : "profile.lua") );
    if(0 != luaL_dofile(myLuaState, (argc > 3 ? argv[3] : "profile.lua") )) {
        ERR(lua_tostring(myLuaState,-1)<< " occured in scripting block");
    }

    EdgeBasedGraphFactory::SpeedProfileProperties speedProfile;

    if(0 != luaL_dostring( myLuaState, "return traffic_signal_penalty\n")) {
        ERR(lua_tostring(myLuaState,-1)<< " occured in scripting block");
    }
    speedProfile.trafficSignalPenalty = 10*lua_tointeger(myLuaState, -1);

    if(0 != luaL_dostring( myLuaState, "return u_turn_penalty\n")) {
        ERR(lua_tostring(myLuaState,-1)<< " occured in scripting block");
    }
    speedProfile.uTurnPenalty = 10*lua_tointeger(myLuaState, -1);

    speedProfile.has_turn_penalty_function = lua_function_exists( myLuaState, "turn_function" );

    std::vector<ImportEdge> edgeList;
    NodeID nodeBasedNodeNumber = readBinaryOSRMGraphFromStream(in, edgeList, bollardNodes, trafficLightNodes, &internalToExternalNodeMapping, inputRestrictions);
    in.close();
    INFO(inputRestrictions.size() << " restrictions, " << bollardNodes.size() << " bollard nodes, " << trafficLightNodes.size() << " traffic lights");
    if(0 == edgeList.size())
        ERR("The input data is broken. It is impossible to do any turns in this graph");

    /***
     * Building an edge-expanded graph from node-based input an turn restrictions
     */

    INFO("Generating edge-expanded graph representation");
    EdgeBasedGraphFactory * edgeBasedGraphFactory = new EdgeBasedGraphFactory (nodeBasedNodeNumber, edgeList, bollardNodes, trafficLightNodes, inputRestrictions, internalToExternalNodeMapping, speedProfile);
    std::vector<ImportEdge>().swap(edgeList);
    edgeBasedGraphFactory->Run(edgeOut.c_str(), myLuaState);
    std::vector<_Restriction>().swap(inputRestrictions);
    std::vector<NodeID>().swap(bollardNodes);
    std::vector<NodeID>().swap(trafficLightNodes);
    NodeID edgeBasedNodeNumber = edgeBasedGraphFactory->GetNumberOfNodes();
    DeallocatingVector<EdgeBasedEdge> edgeBasedEdgeList;
    edgeBasedGraphFactory->GetEdgeBasedEdges(edgeBasedEdgeList);
    DeallocatingVector<EdgeBasedGraphFactory::EdgeBasedNode> nodeBasedEdgeList;
    edgeBasedGraphFactory->GetEdgeBasedNodes(nodeBasedEdgeList);
    delete edgeBasedGraphFactory;

    /***
     * Writing info on original (node-based) nodes
     */

    INFO("writing node map ...");
    std::ofstream mapOutFile(nodeOut.c_str(), std::ios::binary);
    mapOutFile.write((char *)&(internalToExternalNodeMapping[0]), internalToExternalNodeMapping.size()*sizeof(NodeInfo));
    mapOutFile.close();
    std::vector<NodeInfo>().swap(internalToExternalNodeMapping);

    double expansionHasFinishedTime = get_timestamp() - startupTime;

    /***
     * Building grid-like nearest-neighbor data structure
     */

    INFO("building grid ...");
    WritableGrid * writeableGrid = new WritableGrid();
    writeableGrid->ConstructGrid(nodeBasedEdgeList, ramIndexOut.c_str(), fileIndexOut.c_str());
    delete writeableGrid;
    IteratorbasedCRC32<DeallocatingVector<EdgeBasedGraphFactory::EdgeBasedNode> > crc32;
    unsigned crc32OfNodeBasedEdgeList = crc32(nodeBasedEdgeList.begin(), nodeBasedEdgeList.end() );
    nodeBasedEdgeList.clear();
    INFO("CRC32 based checksum is " << crc32OfNodeBasedEdgeList);

    /***
     * Contracting the edge-expanded graph
     */

    INFO("initializing contractor");
    Contractor* contractor = new Contractor( edgeBasedNodeNumber, edgeBasedEdgeList );
    double contractionStartedTimestamp(get_timestamp());
    contractor->Run();
    INFO("Contraction took " << get_timestamp() - contractionStartedTimestamp << " sec");

    DeallocatingVector< QueryEdge > contractedEdgeList;
    contractor->GetEdges( contractedEdgeList );
    delete contractor;

    /***
     * Sorting contracted edges in a way that the static query graph can read some in in-place.
     */

    INFO("Building Node Array");
    std::sort(contractedEdgeList.begin(), contractedEdgeList.end());
    unsigned numberOfNodes = 0;
    unsigned numberOfEdges = contractedEdgeList.size();
    INFO("Serializing compacted graph");
    std::ofstream edgeOutFile(graphOut.c_str(), std::ios::binary);

    BOOST_FOREACH(const QueryEdge & edge, contractedEdgeList) {
        if(edge.source > numberOfNodes) {
            numberOfNodes = edge.source;
        }
        if(edge.target > numberOfNodes) {
            numberOfNodes = edge.target;
        }
    }
    numberOfNodes+=1;

    std::vector< StaticGraph<EdgeData>::_StrNode > _nodes;
    _nodes.resize( numberOfNodes + 1 );

    StaticGraph<EdgeData>::EdgeIterator edge = 0;
    StaticGraph<EdgeData>::EdgeIterator position = 0;
    for ( StaticGraph<EdgeData>::NodeIterator node = 0; node <= numberOfNodes; ++node ) {
        StaticGraph<EdgeData>::EdgeIterator lastEdge = edge;
        while ( edge < numberOfEdges && contractedEdgeList[edge].source == node )
            ++edge;
        _nodes[node].firstEdge = position; //=edge
        position += edge - lastEdge; //remove
    }
    ++numberOfNodes;
    //Serialize numberOfNodes, nodes
    edgeOutFile.write((char*) &crc32OfNodeBasedEdgeList, sizeof(unsigned));
    edgeOutFile.write((char*) &numberOfNodes, sizeof(unsigned));
    edgeOutFile.write((char*) &_nodes[0], sizeof(StaticGraph<EdgeData>::_StrNode)*(numberOfNodes));
    //Serialize number of Edges
    edgeOutFile.write((char*) &position, sizeof(unsigned));
    --numberOfNodes;
    edge = 0;
    int usedEdgeCounter = 0;
    StaticGraph<EdgeData>::_StrEdge currentEdge;
    for ( StaticGraph<EdgeData>::NodeIterator node = 0; node < numberOfNodes; ++node ) {
        for ( StaticGraph<EdgeData>::EdgeIterator i = _nodes[node].firstEdge, e = _nodes[node+1].firstEdge; i != e; ++i ) {
            assert(node != contractedEdgeList[edge].target);
            currentEdge.target = contractedEdgeList[edge].target;
            currentEdge.data = contractedEdgeList[edge].data;
            if(currentEdge.data.distance <= 0) {
                INFO("Edge: " << i << ",source: " << contractedEdgeList[edge].source << ", target: " << contractedEdgeList[edge].target << ", dist: " << currentEdge.data.distance);
                ERR("Failed at edges of node " << node << " of " << numberOfNodes);
            }
            //Serialize edges
            edgeOutFile.write((char*) &currentEdge, sizeof(StaticGraph<EdgeData>::_StrEdge));
            ++edge;
            ++usedEdgeCounter;
        }
    }
    double endTime = (get_timestamp() - startupTime);
    INFO("Expansion  : " << (nodeBasedNodeNumber/expansionHasFinishedTime) << " nodes/sec and "<< (edgeBasedNodeNumber/expansionHasFinishedTime) << " edges/sec");
    INFO("Contraction: " << (edgeBasedNodeNumber/expansionHasFinishedTime) << " nodes/sec and "<< usedEdgeCounter/endTime << " edges/sec");

    edgeOutFile.close();
    //cleanedEdgeList.clear();
    _nodes.clear();
    INFO("finished preprocessing");
    return 0;
}
<commit_msg>Catching any left-over exception that may occur during preprocessing (stxxl)<commit_after>/*
    open source routing machine
    Copyright (C) Dennis Luxen, 2010

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU AFFERO General Public License as published by
the Free Software Foundation; either version 3 of the License, or
any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
or see http://www.gnu.org/licenses/agpl.txt.
 */

#include "Algorithms/IteratorBasedCRC32.h"
#include "Contractor/Contractor.h"
#include "Contractor/EdgeBasedGraphFactory.h"
#include "DataStructures/BinaryHeap.h"
#include "DataStructures/DeallocatingVector.h"
#include "DataStructures/NNGrid.h"
#include "DataStructures/QueryEdge.h"
#include "Util/BaseConfiguration.h"
#include "Util/GraphLoader.h"
#include "Util/InputFileUtil.h"
#include "Util/LuaUtil.h"
#include "Util/OpenMPWrapper.h"
#include "Util/StringUtil.h"
#include "typedefs.h"

#include <boost/foreach.hpp>

#include <luabind/luabind.hpp>

#include <fstream>
#include <istream>
#include <iostream>
#include <cstring>
#include <string>
#include <vector>

typedef QueryEdge::EdgeData EdgeData;
typedef DynamicGraph<EdgeData>::InputEdge InputEdge;
typedef StaticGraph<EdgeData>::InputEdge StaticEdge;
typedef BaseConfiguration ContractorConfiguration;

std::vector<NodeInfo> internalToExternalNodeMapping;
std::vector<_Restriction> inputRestrictions;
std::vector<NodeID> bollardNodes;
std::vector<NodeID> trafficLightNodes;
std::vector<ImportEdge> edgeList;

int main (int argc, char *argv[]) {
    try {
        if(argc < 3) {
            ERR("usage: " << std::endl << argv[0] << " <osrm-data> <osrm-restrictions> [<profile>]");
        }

        double startupTime = get_timestamp();
        unsigned numberOfThreads = omp_get_num_procs();
        if(testDataFile("contractor.ini")) {
            ContractorConfiguration contractorConfig("contractor.ini");
            unsigned rawNumber = stringToInt(contractorConfig.GetParameter("Threads"));
            if(rawNumber != 0 && rawNumber <= numberOfThreads)
                numberOfThreads = rawNumber;
        }
        omp_set_num_threads(numberOfThreads);

        INFO("Using restrictions from file: " << argv[2]);
        std::ifstream restrictionsInstream(argv[2], std::ios::binary);
        if(!restrictionsInstream.good()) {
            ERR("Could not access <osrm-restrictions> files");
        }
        _Restriction restriction;
        unsigned usableRestrictionsCounter(0);
        restrictionsInstream.read((char*)&usableRestrictionsCounter, sizeof(unsigned));
        inputRestrictions.resize(usableRestrictionsCounter);
        restrictionsInstream.read((char *)&(inputRestrictions[0]), usableRestrictionsCounter*sizeof(_Restriction));
        restrictionsInstream.close();

        std::ifstream in;
        in.open (argv[1], std::ifstream::in | std::ifstream::binary);
        if (!in.is_open()) {
            ERR("Cannot open " << argv[1]);
        }

        std::string nodeOut(argv[1]);		nodeOut += ".nodes";
        std::string edgeOut(argv[1]);		edgeOut += ".edges";
        std::string graphOut(argv[1]);		graphOut += ".hsgr";
        std::string ramIndexOut(argv[1]);	ramIndexOut += ".ramIndex";
        std::string fileIndexOut(argv[1]);	fileIndexOut += ".fileIndex";

        /*** Setup Scripting Environment ***/
        if(!testDataFile( (argc > 3 ? argv[3] : "profile.lua") )) {
            ERR("Need profile.lua to apply traffic signal penalty");
        }

        // Create a new lua state
        lua_State *myLuaState = luaL_newstate();

        // Connect LuaBind to this lua state
        luabind::open(myLuaState);

        //open utility libraries string library;
        luaL_openlibs(myLuaState);

        //adjust lua load path
        luaAddScriptFolderToLoadPath( myLuaState, (argc > 3 ? argv[3] : "profile.lua") );

        // Now call our function in a lua script
        INFO("Parsing speedprofile from " << (argc > 3 ? argv[3] : "profile.lua") );
        if(0 != luaL_dofile(myLuaState, (argc > 3 ? argv[3] : "profile.lua") )) {
            ERR(lua_tostring(myLuaState,-1)<< " occured in scripting block");
        }

        EdgeBasedGraphFactory::SpeedProfileProperties speedProfile;

        if(0 != luaL_dostring( myLuaState, "return traffic_signal_penalty\n")) {
            ERR(lua_tostring(myLuaState,-1)<< " occured in scripting block");
        }
        speedProfile.trafficSignalPenalty = 10*lua_tointeger(myLuaState, -1);

        if(0 != luaL_dostring( myLuaState, "return u_turn_penalty\n")) {
            ERR(lua_tostring(myLuaState,-1)<< " occured in scripting block");
        }
        speedProfile.uTurnPenalty = 10*lua_tointeger(myLuaState, -1);

        speedProfile.has_turn_penalty_function = lua_function_exists( myLuaState, "turn_function" );

        std::vector<ImportEdge> edgeList;
        NodeID nodeBasedNodeNumber = readBinaryOSRMGraphFromStream(in, edgeList, bollardNodes, trafficLightNodes, &internalToExternalNodeMapping, inputRestrictions);
        in.close();
        INFO(inputRestrictions.size() << " restrictions, " << bollardNodes.size() << " bollard nodes, " << trafficLightNodes.size() << " traffic lights");
        if(0 == edgeList.size())
            ERR("The input data is broken. It is impossible to do any turns in this graph");

        /***
         * Building an edge-expanded graph from node-based input an turn restrictions
         */

        INFO("Generating edge-expanded graph representation");
        EdgeBasedGraphFactory * edgeBasedGraphFactory = new EdgeBasedGraphFactory (nodeBasedNodeNumber, edgeList, bollardNodes, trafficLightNodes, inputRestrictions, internalToExternalNodeMapping, speedProfile);
        std::vector<ImportEdge>().swap(edgeList);
        edgeBasedGraphFactory->Run(edgeOut.c_str(), myLuaState);
        std::vector<_Restriction>().swap(inputRestrictions);
        std::vector<NodeID>().swap(bollardNodes);
        std::vector<NodeID>().swap(trafficLightNodes);
        NodeID edgeBasedNodeNumber = edgeBasedGraphFactory->GetNumberOfNodes();
        DeallocatingVector<EdgeBasedEdge> edgeBasedEdgeList;
        edgeBasedGraphFactory->GetEdgeBasedEdges(edgeBasedEdgeList);
        DeallocatingVector<EdgeBasedGraphFactory::EdgeBasedNode> nodeBasedEdgeList;
        edgeBasedGraphFactory->GetEdgeBasedNodes(nodeBasedEdgeList);
        delete edgeBasedGraphFactory;

        /***
         * Writing info on original (node-based) nodes
         */

        INFO("writing node map ...");
        std::ofstream mapOutFile(nodeOut.c_str(), std::ios::binary);
        mapOutFile.write((char *)&(internalToExternalNodeMapping[0]), internalToExternalNodeMapping.size()*sizeof(NodeInfo));
        mapOutFile.close();
        std::vector<NodeInfo>().swap(internalToExternalNodeMapping);

        double expansionHasFinishedTime = get_timestamp() - startupTime;

        /***
         * Building grid-like nearest-neighbor data structure
         */

        INFO("building grid ...");
        WritableGrid * writeableGrid = new WritableGrid();
        writeableGrid->ConstructGrid(nodeBasedEdgeList, ramIndexOut.c_str(), fileIndexOut.c_str());
        delete writeableGrid;
        IteratorbasedCRC32<DeallocatingVector<EdgeBasedGraphFactory::EdgeBasedNode> > crc32;
        unsigned crc32OfNodeBasedEdgeList = crc32(nodeBasedEdgeList.begin(), nodeBasedEdgeList.end() );
        nodeBasedEdgeList.clear();
        INFO("CRC32 based checksum is " << crc32OfNodeBasedEdgeList);

        /***
         * Contracting the edge-expanded graph
         */

        INFO("initializing contractor");
        Contractor* contractor = new Contractor( edgeBasedNodeNumber, edgeBasedEdgeList );
        double contractionStartedTimestamp(get_timestamp());
        contractor->Run();
        INFO("Contraction took " << get_timestamp() - contractionStartedTimestamp << " sec");

        DeallocatingVector< QueryEdge > contractedEdgeList;
        contractor->GetEdges( contractedEdgeList );
        delete contractor;

        /***
         * Sorting contracted edges in a way that the static query graph can read some in in-place.
         */

        INFO("Building Node Array");
        std::sort(contractedEdgeList.begin(), contractedEdgeList.end());
        unsigned numberOfNodes = 0;
        unsigned numberOfEdges = contractedEdgeList.size();
        INFO("Serializing compacted graph");
        std::ofstream edgeOutFile(graphOut.c_str(), std::ios::binary);

        BOOST_FOREACH(const QueryEdge & edge, contractedEdgeList) {
            if(edge.source > numberOfNodes) {
                numberOfNodes = edge.source;
            }
            if(edge.target > numberOfNodes) {
                numberOfNodes = edge.target;
            }
        }
        numberOfNodes+=1;

        std::vector< StaticGraph<EdgeData>::_StrNode > _nodes;
        _nodes.resize( numberOfNodes + 1 );

        StaticGraph<EdgeData>::EdgeIterator edge = 0;
        StaticGraph<EdgeData>::EdgeIterator position = 0;
        for ( StaticGraph<EdgeData>::NodeIterator node = 0; node <= numberOfNodes; ++node ) {
            StaticGraph<EdgeData>::EdgeIterator lastEdge = edge;
            while ( edge < numberOfEdges && contractedEdgeList[edge].source == node )
                ++edge;
            _nodes[node].firstEdge = position; //=edge
            position += edge - lastEdge; //remove
        }
        ++numberOfNodes;
        //Serialize numberOfNodes, nodes
        edgeOutFile.write((char*) &crc32OfNodeBasedEdgeList, sizeof(unsigned));
        edgeOutFile.write((char*) &numberOfNodes, sizeof(unsigned));
        edgeOutFile.write((char*) &_nodes[0], sizeof(StaticGraph<EdgeData>::_StrNode)*(numberOfNodes));
        //Serialize number of Edges
        edgeOutFile.write((char*) &position, sizeof(unsigned));
        --numberOfNodes;
        edge = 0;
        int usedEdgeCounter = 0;
        StaticGraph<EdgeData>::_StrEdge currentEdge;
        for ( StaticGraph<EdgeData>::NodeIterator node = 0; node < numberOfNodes; ++node ) {
            for ( StaticGraph<EdgeData>::EdgeIterator i = _nodes[node].firstEdge, e = _nodes[node+1].firstEdge; i != e; ++i ) {
                assert(node != contractedEdgeList[edge].target);
                currentEdge.target = contractedEdgeList[edge].target;
                currentEdge.data = contractedEdgeList[edge].data;
                if(currentEdge.data.distance <= 0) {
                    INFO("Edge: " << i << ",source: " << contractedEdgeList[edge].source << ", target: " << contractedEdgeList[edge].target << ", dist: " << currentEdge.data.distance);
                    ERR("Failed at edges of node " << node << " of " << numberOfNodes);
                }
                //Serialize edges
                edgeOutFile.write((char*) &currentEdge, sizeof(StaticGraph<EdgeData>::_StrEdge));
                ++edge;
                ++usedEdgeCounter;
            }
        }
        double endTime = (get_timestamp() - startupTime);
        INFO("Expansion  : " << (nodeBasedNodeNumber/expansionHasFinishedTime) << " nodes/sec and "<< (edgeBasedNodeNumber/expansionHasFinishedTime) << " edges/sec");
        INFO("Contraction: " << (edgeBasedNodeNumber/expansionHasFinishedTime) << " nodes/sec and "<< usedEdgeCounter/endTime << " edges/sec");

        edgeOutFile.close();
        //cleanedEdgeList.clear();
        _nodes.clear();
        INFO("finished preprocessing");
    } catch (std::exception &e) {
        ERR("Exception occured: " << e.what());
    }
    return 0;
}
<|endoftext|>


<commit_before>#pragma once

#include <future>
#include <agency/execution_categories.hpp>
#include <agency/functional.hpp>
#include <functional>

namespace agency
{

class sequential_executor
{
  public:
    using execution_category = sequential_execution_tag;

    template<class Function, class T>
    void execute(Function f, size_t n, T shared_init)
    {
      auto shared_parm = agency::decay_construct(shared_init);

      for(size_t i = 0; i < n; ++i)
      {
        f(i, shared_parm);
      }
    }

    template<class Function, class T>
    std::future<void> async_execute(Function f, size_t n, T shared_init)
    {
      return std::async(std::launch::deferred, [=]
      {
        this->execute(f, n, shared_init);
      });
    }
};

} // end agency

<commit_msg>Receive shared initializers by forwarding reference in sequential_executor<commit_after>#pragma once

#include <future>
#include <agency/execution_categories.hpp>
#include <agency/functional.hpp>
#include <functional>

namespace agency
{

class sequential_executor
{
  public:
    using execution_category = sequential_execution_tag;

    template<class Function, class T>
    void execute(Function f, size_t n, T&& shared_init)
    {
      auto shared_parm = agency::decay_construct(std::forward<T>(shared_init));

      for(size_t i = 0; i < n; ++i)
      {
        f(i, shared_parm);
      }
    }

    template<class Function, class T>
    std::future<void> async_execute(Function f, size_t n, T&& shared_init)
    {
      return std::async(std::launch::deferred, [=]
      {
        this->execute(f, n, shared_init);
      });
    }
};

} // end agency

<|endoftext|>


<commit_before>// Licensed GNU LGPL v3 or later: http://www.gnu.org/licenses/lgpl.html
// rapicorn-zintern - small C source compression utility
#include <cxxaux.hh>
#include <glib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <zlib.h>
#include <string>

typedef Rapicorn::uint8 uint8;
typedef std::string String;

namespace {

static void     zintern_error  (const char     *format,
                                ...) RAPICORN_PRINTF (1, 2);

static void
zintern_error  (const char     *format,
                ...)
{
  gchar *buffer;
  va_list args;
  va_start (args, format);
  buffer = g_strdup_vprintf (format, args);
  va_end (args);
  g_printerr ("\nERROR: %s\n", buffer);
  _exit (1);
  g_free (buffer);
}

static bool use_compression = FALSE;
static bool use_base_name = FALSE;
static bool break_at_newlines = FALSE;
static bool as_resource = false;

typedef struct {
  uint pos;
  bool pad;
} Config;
static Config config_init = { 0, 0 };

static inline void
print_uchar (Config *config,
	     uint8 d)
{
  if (config->pos > 70)
    {
      printf ("\"\n  \"");
      config->pos = 3;
      config->pad = FALSE;
    }
  if (d == '\\')
    {
      printf ("\\\\");
      config->pos += 2;
    }
  else if (d == '\n')
    {
      printf ("\\n");
      config->pos += 2;
      if (break_at_newlines && config->pos > 3)
        config->pos |= 1 << 31;
    }
  else if (d == '"')
    {
      printf ("\\\"");
      config->pos += 2;
    }
  else if (d < 33 || d > 126 || d == '?')
    {
      printf ("\\%o", d);
      config->pos += 1 + 1 + (d > 7) + (d > 63);
      config->pad = d < 64;
      return;
    }
  else if (config->pad && d >= '0' && d <= '9')
    {
      printf ("\"\"");
      printf ("%c", d);
      config->pos += 3;
    }
  else
    {
      printf ("%c", d);
      config->pos += 1;
    }
  config->pad = FALSE;
}

#define to_upper(c)     ((c) >='a' && (c) <='z' ? (c) - 'a' + 'A' : (c))
#define is_alnum(c)     (((c) >='A' && (c) <='Z') || ((c) >='a' && (c) <='z') || ((c) >='0' && (c) <='9'))
static String
to_cupper (const String &str)
{
  String s (str);
  for (uint i = 0; i < s.size(); i++)
    if (is_alnum (s[i]))
      s[i] = to_upper (s[i]);
    else
      s[i] = '_';
  return s;
}

static void
gen_zfile (const char *name,
	   const char *file)
{
  FILE *f = fopen (file, "r");
  uint8 *data = NULL;
  uint i, dlen = 0, mlen = 0;
  Bytef *cdata;
  uLongf clen;
  gchar *basefile = g_path_get_basename (file);
  String fname = use_base_name ? basefile : file;
  g_free (basefile); basefile = NULL;
  Config config;
  if (!f)
    zintern_error ("failed to open \"%s\": %s", file, g_strerror (errno));
  do
    {
      if (mlen <= dlen + 1024)
	{
	  mlen += 8192;
	  data = g_renew (uint8, data, mlen);
	}
      dlen += fread (data + dlen, 1, mlen - dlen, f);
    }
  while (!feof (f));

  if (ferror (f))
    zintern_error ("failed to read from \"%s\": %s", file, g_strerror (errno));

  if (use_compression || as_resource)
    {
      int result;
      const char *err;
      clen = dlen + dlen / 100 + 64;
      cdata = g_new (uint8, clen);
      result = compress2 (cdata, &clen, data, dlen, Z_BEST_COMPRESSION);
      switch (result)
	{
	case Z_OK:
	  err = NULL;
	  break;
	case Z_MEM_ERROR:
	  err = "out of memory";
	  break;
	case Z_BUF_ERROR:
	  err = "insufficient buffer size";
	  break;
	default:
	  err = "unknown error";
	  break;
	}
      if (err)
	zintern_error ("while compressing \"%s\": %s", file, err);
    }
  else
    {
      clen = dlen;
      cdata = data;
    }

  g_print ("/* rapicorn-zintern file dump of %s */\n", file);

  if (as_resource)
    {
      if (name[0] == '/')
        g_error ("invalid absolute resource path (must be relative): %s", name);
      /* two things to consider for using the compressed data:
       * 1) for the reader code, pack_size + 1 must be smaller than data_size to identify compressed data.
       * 2) using compressed data requires runtime unpacking overhead and extra dynamic memory allocation,
       *    so it should provide a *significant* benefit if it's used.
       */
      const bool compress_resource = clen <= 0.75 * dlen && clen + 1 < dlen;
      const size_t rlen = compress_resource ? clen : dlen;
      const uint8 *rdata = rlen == dlen ? data : cdata;
      gchar *ident = g_strcanon (g_strdup (name), "0123456789abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ", '_');

      config = config_init;
      printf ("RAPICORN_STATIC_RESOURCE_DATA (%s) =\n  \"", ident);
      for (i = 0; i < rlen; i++)
        print_uchar (&config, rdata[i]);
      printf ("\"; // %lu + 1\n", rlen);

      config = config_init;
      printf ("RAPICORN_STATIC_RESOURCE_ENTRY (%s, \"", ident);
      for (i = 0; i < strlen (name); i++)
        print_uchar (&config, name[i]);
      printf ("\", %u);\n", dlen);
      g_free (ident);
    }
  else
    {
      config = config_init;
      printf ("#define %s_NAME \"", to_cupper (name).c_str());
      for (i = 0; i < fname.size(); i++)
        print_uchar (&config, fname[i]);
      printf ("\"\n");

      printf ("#define %s_SIZE (%u)\n", to_cupper (name).c_str(), dlen);

      config = config_init;
      printf ("static const unsigned char %s_DATA[%lu + 1] =\n", to_cupper (name).c_str(), clen);
      printf ("( \"");
      for (i = 0; i < clen; i++)
        print_uchar (&config, cdata[i]);
      printf ("\");\n");
    }

  fclose (f);
  g_free (data);
  if (cdata != data)
    g_free (cdata);
}

static int
help (char *arg)
{
  g_printerr ("usage: rapicorn-zintern [-h] [-b] [-z] [[name file]...]\n");
  g_printerr ("  -h  Print usage information\n");
  g_printerr ("  -b  Strip directories from file names\n");
  g_printerr ("  -n  Break output lines after newlines raw data\n");
  g_printerr ("  -r  Produce Rapicorn resource declarations\n");
  g_printerr ("  -z  Compress data blocks with libz\n");
  g_printerr ("Parse (name, file) pairs and generate C source\n");
  g_printerr ("containing inlined data blocks of the files given.\n");
  return arg != NULL;
}

extern "C" int
main (int   argc,
      char *argv[])
{
  GSList *plist = NULL;

  for (int i = 1; i < argc; i++)
    {
      if (strcmp ("-z", argv[i]) == 0)
	{
	  use_compression = TRUE;
	}
      else if (strcmp ("-r", argv[i]) == 0)
	{
	  as_resource = true;
	}
      else if (strcmp ("-b", argv[i]) == 0)
	{
	  use_base_name = TRUE;
	}
      else if (strcmp ("-n", argv[i]) == 0)
	{
	  break_at_newlines = TRUE;
	}
      else if (strcmp ("-h", argv[i]) == 0)
	{
	  return help (NULL);
	}
      else
	plist = g_slist_append (plist, argv[i]);
    }

  if (argc <= 1)
    return help (NULL);

  while (plist && plist->next)
    {
      const char *name = (char*) plist->data;
      GSList *tmp = plist;
      plist = tmp->next;
      g_slist_free_1 (tmp);
      const char *file = (char*) plist->data;
      tmp = plist;
      plist = tmp->next;
      g_slist_free_1 (tmp);
      gen_zfile (name, file);
    }

  return 0;
}

} // anon
<commit_msg>RCORE: zintern: fix bool constants<commit_after>// Licensed GNU LGPL v3 or later: http://www.gnu.org/licenses/lgpl.html
// rapicorn-zintern - small C source compression utility
#include "cxxaux.hh"
#include <glib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <zlib.h>
#include <string>
using namespace Rapicorn;

typedef std::string String;

static void zintern_error  (const char *format, ...) RAPICORN_PRINTF (1, 2);

static void
zintern_error (const char *format, ...)
{
  char buffer[4096];
  va_list args;
  va_start (args, format);
  vsnprintf (buffer, sizeof (buffer), format, args);
  va_end (args);
  buffer[sizeof (buffer) - 1] = 0;
  fprintf (stderr, "\nERROR: %s\n", buffer);
  _exit (1);
}

static bool use_compression = false;
static bool use_base_name = false;
static bool break_at_newlines = false;
static bool as_resource = false;

typedef struct {
  uint pos;
  bool pad;
} Config;
static Config config_init = { 0, 0 };

static inline void
print_uchar (Config *config,
	     uint8 d)
{
  if (config->pos > 70)
    {
      printf ("\"\n  \"");
      config->pos = 3;
      config->pad = false;
    }
  if (d == '\\')
    {
      printf ("\\\\");
      config->pos += 2;
    }
  else if (d == '\n')
    {
      printf ("\\n");
      config->pos += 2;
      if (break_at_newlines && config->pos > 3)
        config->pos |= 1 << 31;
    }
  else if (d == '"')
    {
      printf ("\\\"");
      config->pos += 2;
    }
  else if (d < 33 || d > 126 || d == '?')
    {
      printf ("\\%o", d);
      config->pos += 1 + 1 + (d > 7) + (d > 63);
      config->pad = d < 64;
      return;
    }
  else if (config->pad && d >= '0' && d <= '9')
    {
      printf ("\"\"");
      printf ("%c", d);
      config->pos += 3;
    }
  else
    {
      printf ("%c", d);
      config->pos += 1;
    }
  config->pad = false;
}

#define to_upper(c)     ((c) >='a' && (c) <='z' ? (c) - 'a' + 'A' : (c))
#define is_alnum(c)     (((c) >='A' && (c) <='Z') || ((c) >='a' && (c) <='z') || ((c) >='0' && (c) <='9'))
static String
to_cupper (const String &str)
{
  String s (str);
  for (uint i = 0; i < s.size(); i++)
    if (is_alnum (s[i]))
      s[i] = to_upper (s[i]);
    else
      s[i] = '_';
  return s;
}

static void
gen_zfile (const char *name,
	   const char *file)
{
  FILE *f = fopen (file, "r");
  uint8 *data = NULL;
  uint i, dlen = 0, mlen = 0;
  Bytef *cdata;
  uLongf clen;
  gchar *basefile = g_path_get_basename (file);
  String fname = use_base_name ? basefile : file;
  g_free (basefile); basefile = NULL;
  Config config;
  if (!f)
    zintern_error ("failed to open \"%s\": %s", file, g_strerror (errno));
  do
    {
      if (mlen <= dlen + 1024)
	{
	  mlen += 8192;
	  data = g_renew (uint8, data, mlen);
	}
      dlen += fread (data + dlen, 1, mlen - dlen, f);
    }
  while (!feof (f));

  if (ferror (f))
    zintern_error ("failed to read from \"%s\": %s", file, g_strerror (errno));

  if (use_compression || as_resource)
    {
      int result;
      const char *err;
      clen = dlen + dlen / 100 + 64;
      cdata = g_new (uint8, clen);
      result = compress2 (cdata, &clen, data, dlen, Z_BEST_COMPRESSION);
      switch (result)
	{
	case Z_OK:
	  err = NULL;
	  break;
	case Z_MEM_ERROR:
	  err = "out of memory";
	  break;
	case Z_BUF_ERROR:
	  err = "insufficient buffer size";
	  break;
	default:
	  err = "unknown error";
	  break;
	}
      if (err)
	zintern_error ("while compressing \"%s\": %s", file, err);
    }
  else
    {
      clen = dlen;
      cdata = data;
    }

  g_print ("/* rapicorn-zintern file dump of %s */\n", file);

  if (as_resource)
    {
      if (name[0] == '/')
        g_error ("invalid absolute resource path (must be relative): %s", name);
      /* two things to consider for using the compressed data:
       * 1) for the reader code, pack_size + 1 must be smaller than data_size to identify compressed data.
       * 2) using compressed data requires runtime unpacking overhead and extra dynamic memory allocation,
       *    so it should provide a *significant* benefit if it's used.
       */
      const bool compress_resource = clen <= 0.75 * dlen && clen + 1 < dlen;
      const size_t rlen = compress_resource ? clen : dlen;
      const uint8 *rdata = rlen == dlen ? data : cdata;
      gchar *ident = g_strcanon (g_strdup (name), "0123456789abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ", '_');

      config = config_init;
      printf ("RAPICORN_STATIC_RESOURCE_DATA (%s) =\n  \"", ident);
      for (i = 0; i < rlen; i++)
        print_uchar (&config, rdata[i]);
      printf ("\"; // %lu + 1\n", rlen);

      config = config_init;
      printf ("RAPICORN_STATIC_RESOURCE_ENTRY (%s, \"", ident);
      for (i = 0; i < strlen (name); i++)
        print_uchar (&config, name[i]);
      printf ("\", %u);\n", dlen);
      g_free (ident);
    }
  else
    {
      config = config_init;
      printf ("#define %s_NAME \"", to_cupper (name).c_str());
      for (i = 0; i < fname.size(); i++)
        print_uchar (&config, fname[i]);
      printf ("\"\n");

      printf ("#define %s_SIZE (%u)\n", to_cupper (name).c_str(), dlen);

      config = config_init;
      printf ("static const unsigned char %s_DATA[%lu + 1] =\n", to_cupper (name).c_str(), clen);
      printf ("( \"");
      for (i = 0; i < clen; i++)
        print_uchar (&config, cdata[i]);
      printf ("\");\n");
    }

  fclose (f);
  g_free (data);
  if (cdata != data)
    g_free (cdata);
}

static int
help (char *arg)
{
  g_printerr ("usage: rapicorn-zintern [-h] [-b] [-z] [[name file]...]\n");
  g_printerr ("  -h  Print usage information\n");
  g_printerr ("  -b  Strip directories from file names\n");
  g_printerr ("  -n  Break output lines after newlines raw data\n");
  g_printerr ("  -r  Produce Rapicorn resource declarations\n");
  g_printerr ("  -z  Compress data blocks with libz\n");
  g_printerr ("Parse (name, file) pairs and generate C source\n");
  g_printerr ("containing inlined data blocks of the files given.\n");
  return arg != NULL;
}

int
main (int argc, char *argv[])
{
  GSList *plist = NULL;

  for (int i = 1; i < argc; i++)
    {
      if (strcmp ("-z", argv[i]) == 0)
	{
	  use_compression = true;
	}
      else if (strcmp ("-r", argv[i]) == 0)
	{
	  as_resource = true;
	}
      else if (strcmp ("-b", argv[i]) == 0)
	{
	  use_base_name = true;
	}
      else if (strcmp ("-n", argv[i]) == 0)
	{
	  break_at_newlines = true;
	}
      else if (strcmp ("-h", argv[i]) == 0)
	{
	  return help (NULL);
	}
      else
	plist = g_slist_append (plist, argv[i]);
    }

  if (argc <= 1)
    return help (NULL);

  while (plist && plist->next)
    {
      const char *name = (char*) plist->data;
      GSList *tmp = plist;
      plist = tmp->next;
      g_slist_free_1 (tmp);
      const char *file = (char*) plist->data;
      tmp = plist;
      plist = tmp->next;
      g_slist_free_1 (tmp);
      gen_zfile (name, file);
    }

  return 0;
}
<|endoftext|>


<commit_before>/*
 * Copyright 2017-2018 Baidu Inc.
 *
 * 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 "openrasp_hook.h"
#include "openrasp_ini.h"
#include <string>
#include <map>

extern "C" {
#include "ext/pdo/php_pdo_driver.h"
#include "zend_ini.h"
#include "openrasp_shared_alloc.h"
}

/**
 * sql connection alarm
 */
static void connection_via_default_username_policy(char *check_message, sql_connection_entry *sql_connection_p TSRMLS_DC)
{
    zval *policy_array = nullptr;
    MAKE_STD_ZVAL(policy_array);
    array_init(policy_array);
    add_assoc_string(policy_array, "message", check_message, 1);
    add_assoc_long(policy_array, "policy_id", 3006);
    zval *connection_params = nullptr;
    MAKE_STD_ZVAL(connection_params);
    array_init(connection_params);
    add_assoc_string(connection_params, "server", sql_connection_p->server, 1);
    add_assoc_string(connection_params, "host", sql_connection_p->host, 1);
    add_assoc_long(connection_params, "port", sql_connection_p->port);
    add_assoc_string(connection_params, "user", sql_connection_p->username, 1);
    add_assoc_zval(policy_array, "params", connection_params);
    policy_info(policy_array TSRMLS_CC);
    zval_ptr_dtor(&policy_array);
}

void slow_query_alarm(int rows TSRMLS_DC)
{
    zval *attack_params = nullptr;
    MAKE_STD_ZVAL(attack_params);
    ZVAL_LONG(attack_params, rows);
    zval *plugin_message = nullptr;
    MAKE_STD_ZVAL(plugin_message);
    char *message_str = nullptr;
    spprintf(&message_str, 0, _("SQL slow query detected: selected %d rows, exceeding %d"), rows, openrasp_ini.slowquery_min_rows);
    ZVAL_STRING(plugin_message, message_str, 1);
    efree(message_str);
    openrasp_buildin_php_risk_handle(0, "sqlSlowQuery", 100, attack_params, plugin_message TSRMLS_CC);
}

zend_bool check_database_connection_username(INTERNAL_FUNCTION_PARAMETERS, init_connection_t connection_init_func, int enforce_policy)
{
    static const std::multimap<std::string, std::string> database_username_blacklists = {
        {"mysql", "root"},
        {"mssql", "sa"},
        {"pgsql", "postgres"},
        {"oci",   "dbsnmp"},
        {"oci",   "sysman"},
        {"oci",   "system"},
        {"oci",   "sys"}
    };
    sql_connection_entry conn_entry;
    char *check_message = nullptr;
    zend_bool need_block= 0;
    connection_init_func(INTERNAL_FUNCTION_PARAM_PASSTHRU, &conn_entry);
    if (conn_entry.server && conn_entry.username && conn_entry.host)
    {
        auto pos = database_username_blacklists.equal_range(std::string(conn_entry.server));
        while (pos.first != pos.second)
        {
            if (std::string(conn_entry.username) == pos.first->second)
            {
                spprintf(&check_message, 0,
                    _("Connecting to a %s instance using the high privileged account: %s - (%s:%d)"),
                    conn_entry.server,
                    conn_entry.username,
                    conn_entry.host,
                    conn_entry.port);
                break;
            }
            pos.first++;
        }
        if (check_message)
        {
            if (enforce_policy)
            {
                connection_via_default_username_policy(check_message, &conn_entry TSRMLS_CC);
                need_block = 1;
            }
            else
            {
                ulong connection_hash = zend_inline_hash_func(conn_entry.host, strlen(conn_entry.host));
                openrasp_shared_alloc_lock(TSRMLS_C);
                if (!openrasp_shared_hash_exist(connection_hash, OPENRASP_LOG_G(formatted_date_suffix)))
                {
                    connection_via_default_username_policy(check_message, &conn_entry TSRMLS_CC);
                }
                openrasp_shared_alloc_unlock(TSRMLS_C);
            }
            efree(check_message);
        }
    }
    if (conn_entry.host)
    {
        efree(conn_entry.host);
    }
    if (conn_entry.username)
    {
        efree(conn_entry.username);
    }
    return need_block;
}

/*  check sql query clause
*/
void check_query_clause(INTERNAL_FUNCTION_PARAMETERS, char *server, int num)
{
    if (openrasp_check_type_ignored(ZEND_STRL("sql") TSRMLS_CC))
    {
        return;
    }
    int argc = MIN(num, ZEND_NUM_ARGS());
    zval ***args = (zval ***)safe_emalloc(argc, sizeof(zval **), 0);
    if (argc == num &&
        zend_get_parameters_array_ex(argc, args) == SUCCESS &&
        Z_TYPE_PP(args[num - 1]) == IS_STRING)
    {
        zval *params;
        MAKE_STD_ZVAL(params);
        array_init(params);
        add_assoc_zval(params, "query", *args[num - 1]);
        Z_ADDREF_P(*args[num - 1]);
        add_assoc_string(params, "server", server, 1);
        check("sql", params TSRMLS_CC);
    }
    efree(args);
}

long fetch_rows_via_user_function(const char *f_name_str, zend_uint param_count, zval *params[] TSRMLS_DC)
{
    zval function_name, retval;
    INIT_ZVAL(function_name);
    ZVAL_STRING(&function_name, f_name_str, 0);
    if (call_user_function(EG(function_table), nullptr, &function_name, &retval, param_count, params TSRMLS_CC) == SUCCESS
    && Z_TYPE(retval) == IS_LONG)
    {
        return Z_LVAL(retval);
    }
    return 0;
}

<commit_msg>[PHP]修改数据库连接hash计算方法(server-host:port)<commit_after>/*
 * Copyright 2017-2018 Baidu Inc.
 *
 * 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 "openrasp_hook.h"
#include "openrasp_ini.h"
#include <string>
#include <map>

extern "C" {
#include "ext/pdo/php_pdo_driver.h"
#include "zend_ini.h"
#include "openrasp_shared_alloc.h"
}

/**
 * sql connection alarm
 */
static void connection_via_default_username_policy(char *check_message, sql_connection_entry *sql_connection_p TSRMLS_DC)
{
    zval *policy_array = nullptr;
    MAKE_STD_ZVAL(policy_array);
    array_init(policy_array);
    add_assoc_string(policy_array, "message", check_message, 1);
    add_assoc_long(policy_array, "policy_id", 3006);
    zval *connection_params = nullptr;
    MAKE_STD_ZVAL(connection_params);
    array_init(connection_params);
    add_assoc_string(connection_params, "server", sql_connection_p->server, 1);
    add_assoc_string(connection_params, "host", sql_connection_p->host, 1);
    add_assoc_long(connection_params, "port", sql_connection_p->port);
    add_assoc_string(connection_params, "user", sql_connection_p->username, 1);
    add_assoc_zval(policy_array, "params", connection_params);
    policy_info(policy_array TSRMLS_CC);
    zval_ptr_dtor(&policy_array);
}

void slow_query_alarm(int rows TSRMLS_DC)
{
    zval *attack_params = nullptr;
    MAKE_STD_ZVAL(attack_params);
    ZVAL_LONG(attack_params, rows);
    zval *plugin_message = nullptr;
    MAKE_STD_ZVAL(plugin_message);
    char *message_str = nullptr;
    spprintf(&message_str, 0, _("SQL slow query detected: selected %d rows, exceeding %d"), rows, openrasp_ini.slowquery_min_rows);
    ZVAL_STRING(plugin_message, message_str, 1);
    efree(message_str);
    openrasp_buildin_php_risk_handle(0, "sqlSlowQuery", 100, attack_params, plugin_message TSRMLS_CC);
}

zend_bool check_database_connection_username(INTERNAL_FUNCTION_PARAMETERS, init_connection_t connection_init_func, int enforce_policy)
{
    static const std::multimap<std::string, std::string> database_username_blacklists = {
        {"mysql", "root"},
        {"mssql", "sa"},
        {"pgsql", "postgres"},
        {"oci",   "dbsnmp"},
        {"oci",   "sysman"},
        {"oci",   "system"},
        {"oci",   "sys"}
    };
    sql_connection_entry conn_entry;
    char *check_message = nullptr;
    zend_bool need_block= 0;
    connection_init_func(INTERNAL_FUNCTION_PARAM_PASSTHRU, &conn_entry);
    if (conn_entry.server && conn_entry.username && conn_entry.host)
    {
        auto pos = database_username_blacklists.equal_range(std::string(conn_entry.server));
        while (pos.first != pos.second)
        {
            if (std::string(conn_entry.username) == pos.first->second)
            {
                spprintf(&check_message, 0,
                    _("Connecting to a %s instance using the high privileged account: %s - (%s:%d)"),
                    conn_entry.server,
                    conn_entry.username,
                    conn_entry.host,
                    conn_entry.port);
                break;
            }
            pos.first++;
        }
        if (check_message)
        {
            if (enforce_policy)
            {
                connection_via_default_username_policy(check_message, &conn_entry TSRMLS_CC);
                need_block = 1;
            }
            else
            {
                char *server_host_port = nullptr;
                int server_host_port_len = spprintf(&server_host_port, 0, "%s-%s:%d", conn_entry.server, conn_entry.host, conn_entry.port);
                ulong connection_hash = zend_inline_hash_func(server_host_port, server_host_port_len);
                openrasp_shared_alloc_lock(TSRMLS_C);
                if (!openrasp_shared_hash_exist(connection_hash, OPENRASP_LOG_G(formatted_date_suffix)))
                {
                    connection_via_default_username_policy(check_message, &conn_entry TSRMLS_CC);
                }
                openrasp_shared_alloc_unlock(TSRMLS_C);
                efree(server_host_port);
            }
            efree(check_message);
        }
    }
    if (conn_entry.host)
    {
        efree(conn_entry.host);
    }
    if (conn_entry.username)
    {
        efree(conn_entry.username);
    }
    return need_block;
}

/*  check sql query clause
*/
void check_query_clause(INTERNAL_FUNCTION_PARAMETERS, char *server, int num)
{
    if (openrasp_check_type_ignored(ZEND_STRL("sql") TSRMLS_CC))
    {
        return;
    }
    int argc = MIN(num, ZEND_NUM_ARGS());
    zval ***args = (zval ***)safe_emalloc(argc, sizeof(zval **), 0);
    if (argc == num &&
        zend_get_parameters_array_ex(argc, args) == SUCCESS &&
        Z_TYPE_PP(args[num - 1]) == IS_STRING)
    {
        zval *params;
        MAKE_STD_ZVAL(params);
        array_init(params);
        add_assoc_zval(params, "query", *args[num - 1]);
        Z_ADDREF_P(*args[num - 1]);
        add_assoc_string(params, "server", server, 1);
        check("sql", params TSRMLS_CC);
    }
    efree(args);
}

long fetch_rows_via_user_function(const char *f_name_str, zend_uint param_count, zval *params[] TSRMLS_DC)
{
    zval function_name, retval;
    INIT_ZVAL(function_name);
    ZVAL_STRING(&function_name, f_name_str, 0);
    if (call_user_function(EG(function_table), nullptr, &function_name, &retval, param_count, params TSRMLS_CC) == SUCCESS
    && Z_TYPE(retval) == IS_LONG)
    {
        return Z_LVAL(retval);
    }
    return 0;
}

<|endoftext|>


<commit_before>#include "audio_player.h"
#include <QtMath>
#include <QDebug>

//Get the percentage downloaded of an internet file stream, or the buffer level when streaming in blocks.
//QWORD len=BASS_StreamGetFilePosition(stream, BASS_FILEPOS_END); // file/buffer length
//QWORD buf=BASS_StreamGetFilePosition(stream, BASS_FILEPOS_BUFFER); // buffer level
//float progress=buf*100.0/len; // percentage of buffer filled

//void endTrackSync(HSYNC handle, DWORD channel, DWORD data, void * user)
void endTrackSync(HSYNC, DWORD, DWORD, void * user) {
//    BASS_ChannelStop(channel);
//    BASS_ChannelRemoveSync(channel, handle);
    AudioPlayer * player = static_cast<AudioPlayer *>(user);
    emit player -> playbackEnded();
}

AudioPlayer::AudioPlayer(QObject * parent) : QObject(parent) {
    qRegisterMetaType<AudioPlayer::MediaStatus>("MediaStatus");
    qRegisterMetaType<AudioPlayer::MediaState>("MediaState");

    // cheat for cross treadhing
    connect(this, SIGNAL(playbackEnded()), this, SLOT(endOfPlayback()));

    duration = -1;
    notifyInterval = 100;
    volumeVal = 1.0;
    spectrumHeight = 0;
    spectrumBandsCount = 28;

    currentState = StoppedState;

    if (HIWORD(BASS_GetVersion()) != BASSVERSION) {
        throw "An incorrect version of BASS.DLL was loaded";
    }

    if (HIWORD(BASS_FX_GetVersion()) != BASSVERSION) {
        throw "An incorrect version of BASS_FX.DLL was loaded";
    }

    if (!BASS_Init(-1, 44100, 0, NULL, NULL))
        qDebug() << "Init error: " << BASS_ErrorGetCode();
//        throw "Cannot initialize device";

    ///////////////////////////////////////////////
    /// load plugins
    ///////////////////////////////////////////////
    QFileInfoList list = QDir(QCoreApplication::applicationDirPath() + "/libs/bass/plugins").entryInfoList(QDir::Files | QDir::NoDotAndDotDot | QDir::Hidden);

    foreach(QFileInfo file, list) {
        /*int res = */BASS_PluginLoad(file.filePath().toLatin1(), 0);

//        if (res == 0)
//            qDebug() << file.filePath() << BASS_ErrorGetCode();
//        else
//            qDebug() << file.filePath() << res;
    }
    ///////////////////////////////////////////////

    notifyTimer = new NotifyTimer(this);
    connect(notifyTimer, SIGNAL(timeout()), this, SLOT(signalUpdate()));
    connect(notifyTimer, SIGNAL(started()), this, SLOT(started()));
    connect(notifyTimer, SIGNAL(stoped()), this, SLOT(stoped()));

    spectrumTimer = new NotifyTimer(this);
    connect(spectrumTimer, SIGNAL(timeout()), this, SLOT(calcSpectrum()));
    spectrumTimer -> start(25); //40 Hz
}

AudioPlayer::~AudioPlayer() {
    BASS_PluginFree(0);
    notifyTimer -> stop();
    delete notifyTimer;

    spectrumTimer -> stop();
    delete spectrumTimer;
}

int AudioPlayer::getPosition() const {
    return BASS_ChannelBytes2Seconds(chan, BASS_ChannelGetPosition(chan, BASS_POS_BYTE)) * 1000;
}

int AudioPlayer::getDuration() const {
    return duration;
}

int AudioPlayer::getNotifyInterval() {
    return notifyInterval;
}
void AudioPlayer::setNotifyInterval(signed int milis) {
    notifyInterval = milis;
    if (notifyTimer -> isActive())
        notifyTimer -> setInterval(notifyInterval);
}

void AudioPlayer::setMedia(QUrl mediaPath) {
    mediaUri = mediaPath;
}

void AudioPlayer::setSpectrumBandsCount(int bandsCount) {
    spectrumBandsCount = bandsCount;
}
void AudioPlayer::setSpectrumHeight(int newHeight) {
    spectrumHeight = newHeight;
}

AudioPlayer::MediaState AudioPlayer::state() const {
    return currentState;
}

bool AudioPlayer::isPlayed() const {
    return currentState == PlayingState;
}
bool AudioPlayer::isPaused() const {
    return currentState == PausedState;
}
bool AudioPlayer::isStoped() const {
    return currentState == StoppedState;
}

////////////////////////////////////////////////////////////////////////
/// PRIVATE
////////////////////////////////////////////////////////////////////////

int AudioPlayer::openRemoteChannel(QString path) {
    BASS_ChannelStop(chan);
    chan = BASS_StreamCreateURL(path.toStdWString().c_str(), 0, BASS_SAMPLE_FLOAT, NULL, 0);

//    BASS_Encode_Start(channel, "output.wav", BASS_ENCODE_PCM, NULL, 0);

//    BASS_Encode_StartCAFile(channel, 'mp4f', 'aac ', 0, 128000, "output.mp4"); // only macos
//    BASS_Encode_StartCAFile(channel, 'm4af', 'alac', 0, 0, "output.m4a"); // only macos

    if (!chan) {
        int status = BASS_ErrorGetCode();
        if (status == BASS_ERROR_FILEOPEN)// || status == BASS_ERROR_NONET)
            emit remoteUnprocessed();
        qDebug() << "Can't play stream" <<  BASS_ErrorGetCode() << path.toUtf8();
    }
    return chan;
}

int AudioPlayer::openChannel(QString path) {
    BASS_ChannelStop(chan);
    if (!(chan = BASS_StreamCreateFile(false, path.toStdWString().c_str(), 0, 0, BASS_SAMPLE_FLOAT | BASS_ASYNCFILE)))
//    if (!(stream = BASS_StreamCreateFile(false, path.toStdWString().c_str(), 0, 0, BASS_SAMPLE_LOOP))
//        && !(chan = BASS_MusicLoad(false, path.toStdWString().c_str(), 0, 0, BASS_SAMPLE_LOOP | BASS_MUSIC_RAMP | BASS_MUSIC_POSRESET | BASS_MUSIC_STOPBACK | BASS_STREAM_PRESCAN | BASS_MUSIC_AUTOFREE, 1)))
        qDebug() << "Can't play file " <<  BASS_ErrorGetCode() << path.toUtf8();
    return chan;
}

void AudioPlayer::closeChannel() {
    BASS_ChannelStop(chan);
    BASS_ChannelRemoveSync(chan, syncHandle);
    BASS_StreamFree(chan);
//    BASS_MusicFree(chan);
}

////////////////////////////////////////////////////////////////////////
/// SLOTS
////////////////////////////////////////////////////////////////////////

void AudioPlayer::started() {
    currentState = PlayingState;
    emit stateChanged(PlayingState);
}

void AudioPlayer::stoped() {
    currentState = StoppedState;
}

void AudioPlayer::signalUpdate() {
    int curr_pos = BASS_ChannelBytes2Seconds(chan, BASS_ChannelGetPosition(chan, BASS_POS_BYTE)) * 1000;

    emit positionChanged(curr_pos);
}

void AudioPlayer::calcSpectrum() {
    if (spectrumHeight > 0)
        emit spectrumChanged(getSpectrum());
}

void AudioPlayer::slidePosForward() {
    if (currentState == PlayingState || currentState == PausedState) {
        int dur = getDuration();
        int pos = getPosition() + dur / 10;
        if (pos < dur)
            setPosition(pos);
    }
}
void AudioPlayer::slidePosBackward() {
    if (currentState == PlayingState || currentState == PausedState) {
        int pos = getPosition() - (getDuration() / 10);
        if (pos < 0) pos = 0;
        setPosition(pos);
    }
}

//0 to 10000
void AudioPlayer::setChannelVolume(int val) {
    volumeVal = val > 0 ? (val / 10000.0) : 0;
    BASS_ChannelSetAttribute(chan, BASS_ATTRIB_VOL, volumeVal);
    emit volumeChanged(val);
}

void AudioPlayer::slideVolForward() {
    int newVolLevel = getVolume() + 1000;
    if (newVolLevel > 10000) newVolLevel = 10000;
    setChannelVolume(newVolLevel);
}
void AudioPlayer::slideVolBackward() {
    int newVolLevel = getVolume() - 1000;
    if (newVolLevel < 0) newVolLevel = 0;
    setChannelVolume(newVolLevel);
}

// 0 to 10000
void AudioPlayer::setVolume(int val) {
    BASS_SetConfig(BASS_CONFIG_GVOL_STREAM, val);
    emit volumeChanged(val);
}

float AudioPlayer::getSize() const {
    return size;
}

int AudioPlayer::getVolume() const {
    return volumeVal * 10000;
}

//from 0 to 1
float AudioPlayer::getRemoteFileDownloadPosition() {
    if (size == -1) {
        prevDownloadPos = 0;
        DWORD len = BASS_StreamGetFilePosition(chan, BASS_FILEPOS_END);
        size = len + BASS_StreamGetFilePosition(chan, BASS_FILEPOS_START);
    }

    if (prevDownloadPos != 1) {
        float currDownloadPos = ((BASS_StreamGetFilePosition(chan, BASS_FILEPOS_DOWNLOAD)) / size);
        if (prevDownloadPos == currDownloadPos && currDownloadPos > 0.8)
            prevDownloadPos = 1;
        else
            prevDownloadPos = currDownloadPos;
    }
    return prevDownloadPos;
}

QHash<QString, QString> AudioPlayer::getRemoteFileInfo(QString uri) {
    QHash<QString, QString> ret;

    int chUID = BASS_StreamCreateURL(uri.toStdWString().c_str(), 0, 0, NULL, 0);

    if (!chUID)
        return ret;

    float time = BASS_ChannelBytes2Seconds(chUID, BASS_ChannelGetLength(chUID, BASS_POS_BYTE)); // playback duration
    DWORD len = BASS_StreamGetFilePosition(chUID, BASS_FILEPOS_END); // file length
    int bitrate = (len / (125 * time) + 0.5); // average bitrate (Kbps)

    ret.insert("duration", Duration::fromSeconds(time));

    BASS_CHANNELINFO info;
    if (BASS_ChannelGetInfo(chUID, &info)) {
        int size = len + BASS_StreamGetFilePosition(chUID, BASS_FILEPOS_START);
        ret.insert("info", Format::toInfo(Format::toUnits(size), bitrate, info.freq, info.chans));
    }

    BASS_StreamFree(chUID);

    return ret;
}

float AudioPlayer::getBpmValue(QUrl uri) {
    int cochan;

    if (uri.isLocalFile())
        cochan = BASS_StreamCreateFile(false, uri.toLocalFile().toStdWString().c_str(), 0, 0, BASS_SAMPLE_FLOAT | BASS_STREAM_DECODE | BASS_STREAM_PRESCAN | BASS_SAMPLE_MONO);
    else
        cochan = BASS_StreamCreateURL(uri.toString().toStdWString().c_str(), 0, BASS_SAMPLE_FLOAT | BASS_STREAM_DECODE | BASS_SAMPLE_MONO, NULL, 0);

    if (cochan) {
        int playBackDuration = BASS_ChannelBytes2Seconds(cochan, BASS_ChannelGetLength(cochan, BASS_POS_BYTE));
        BASS_ChannelSetAttribute(cochan, BASS_ATTRIB_VOL, 0);
        qDebug() << playBackDuration;
        return BASS_FX_BPM_DecodeGet(cochan,
                              0,
                              60,
                              0, //MAKEWORD(60, 230),
                              BASS_FX_FREESOURCE, //BASS_FX_BPM_BKGRND // BASS_FX_BPM_MULT2
                              NULL, NULL);

//        float last = BASS_FX_BPM_DecodeGet(cochan,
//                              0.0,
//                              playBackDuration,
//                              MAKELONG(85, 90),
//                              BASS_FX_FREESOURCE, //BASS_FX_BPM_BKGRND // BASS_FX_BPM_MULT2
//                              NULL, NULL);

//        qDebug() << last << " " << first;
    } else return 0;
}

QList<int> AudioPlayer::getSpectrum() {
    float fft[1024];
    BASS_ChannelGetData(chan, fft, BASS_DATA_FFT2048);
    QList<int> res;

    int b0 = 0, x, y;

    for (x = 0; x < spectrumBandsCount; x++) {
        float peak = 0;
        int b1 = qPow(2, x * 10.0 / (spectrumBandsCount - 1));
        if (b1 > 1023) b1 = 1023;
        if (b1 <= b0) b1 = b0 + 1; // make sure it uses at least 1 FFT bin
        for (; b0 < b1; b0++)
            if (peak < fft[1 + b0])
                peak = fft[1 + b0];

        y = qSqrt(peak) * 3 * spectrumHeight - 4; // scale it (sqrt to make low values more visible)
        if (y > spectrumHeight) y = spectrumHeight; // cap it

        res.append(y);
    }

    return res;
}

////////////////////////////////////////////////////////////////////////

void AudioPlayer::play() {
    if (currentState == PausedState) {
        resume();
    } else {
        closeChannel();
        if (mediaUri.isEmpty()) {
            emit mediaStatusChanged(NoMedia);
        } else {
            qDebug() << mediaUri.toString();

            if (mediaUri.isLocalFile()) {
                openChannel(mediaUri.toLocalFile());
                size = 0;
                prevDownloadPos = 1;
            } else {
                openRemoteChannel(mediaUri.toString());
                size = -1;
            }

            if (chan) {
                BASS_ChannelSetAttribute(chan, BASS_ATTRIB_VOL, volumeVal);
                duration = BASS_ChannelBytes2Seconds(chan, BASS_ChannelGetLength(chan, BASS_POS_BYTE)) * 1000;
                durationChanged(duration);
                BASS_ChannelPlay(chan, true);
                notifyTimer -> start(notifyInterval);
                //TODO: remove sync and check end of file by timer
                syncHandle = BASS_ChannelSetSync(chan, BASS_SYNC_END, 0, &endTrackSync, this);
//                BASS_SYNC_DOWNLOAD
            } else {
                qDebug() << "Can't play file";
            }
        }
    }
}

void AudioPlayer::pause() {
    notifyTimer -> stop();
    BASS_ChannelPause(chan);
    emit stateChanged(PausedState);
    currentState = PausedState;
}

void AudioPlayer::resume() {
    if (!BASS_ChannelPlay(chan, false)) {
        emit mediaStatusChanged(StalledMedia);
        qDebug() << "Error resuming";
    } else {
        notifyTimer -> start(notifyInterval);
    }
}

void AudioPlayer::stop() {
    closeChannel();
    notifyTimer -> stop();
    emit stateChanged(StoppedState);
}

void AudioPlayer::endOfPlayback() {
    stop();
    closeChannel();
    emit mediaStatusChanged(EndOfMedia);
}

void AudioPlayer::setPosition(int position) {
    BASS_ChannelSetPosition(chan, BASS_ChannelSeconds2Bytes(chan, position / 1000.0), BASS_POS_BYTE);
}
<commit_msg>improve spectrum delay<commit_after>#include "audio_player.h"
#include <QtMath>
#include <QDebug>

//Get the percentage downloaded of an internet file stream, or the buffer level when streaming in blocks.
//QWORD len=BASS_StreamGetFilePosition(stream, BASS_FILEPOS_END); // file/buffer length
//QWORD buf=BASS_StreamGetFilePosition(stream, BASS_FILEPOS_BUFFER); // buffer level
//float progress=buf*100.0/len; // percentage of buffer filled

//void endTrackSync(HSYNC handle, DWORD channel, DWORD data, void * user)
void endTrackSync(HSYNC, DWORD, DWORD, void * user) {
//    BASS_ChannelStop(channel);
//    BASS_ChannelRemoveSync(channel, handle);
    AudioPlayer * player = static_cast<AudioPlayer *>(user);
    emit player -> playbackEnded();
}

AudioPlayer::AudioPlayer(QObject * parent) : QObject(parent) {
    qRegisterMetaType<AudioPlayer::MediaStatus>("MediaStatus");
    qRegisterMetaType<AudioPlayer::MediaState>("MediaState");

    // cheat for cross treadhing
    connect(this, SIGNAL(playbackEnded()), this, SLOT(endOfPlayback()));

    duration = -1;
    notifyInterval = 100;
    volumeVal = 1.0;
    spectrumHeight = 0;
    spectrumBandsCount = 28;

    currentState = StoppedState;

    if (HIWORD(BASS_GetVersion()) != BASSVERSION) {
        throw "An incorrect version of BASS.DLL was loaded";
    }

    if (HIWORD(BASS_FX_GetVersion()) != BASSVERSION) {
        throw "An incorrect version of BASS_FX.DLL was loaded";
    }

    if (!BASS_Init(-1, 44100, 0, NULL, NULL))
        qDebug() << "Init error: " << BASS_ErrorGetCode();
//        throw "Cannot initialize device";

    ///////////////////////////////////////////////
    /// load plugins
    ///////////////////////////////////////////////
    QFileInfoList list = QDir(QCoreApplication::applicationDirPath() + "/libs/bass/plugins").entryInfoList(QDir::Files | QDir::NoDotAndDotDot | QDir::Hidden);

    foreach(QFileInfo file, list) {
        /*int res = */BASS_PluginLoad(file.filePath().toLatin1(), 0);

//        if (res == 0)
//            qDebug() << file.filePath() << BASS_ErrorGetCode();
//        else
//            qDebug() << file.filePath() << res;
    }
    ///////////////////////////////////////////////

    notifyTimer = new NotifyTimer(this);
    connect(notifyTimer, SIGNAL(timeout()), this, SLOT(signalUpdate()));
    connect(notifyTimer, SIGNAL(started()), this, SLOT(started()));
    connect(notifyTimer, SIGNAL(stoped()), this, SLOT(stoped()));

    spectrumTimer = new NotifyTimer(this);
    connect(spectrumTimer, SIGNAL(timeout()), this, SLOT(calcSpectrum()));
    spectrumTimer -> start(25); //40 Hz
}

AudioPlayer::~AudioPlayer() {
    BASS_PluginFree(0);
    notifyTimer -> stop();
    delete notifyTimer;

    spectrumTimer -> stop();
    delete spectrumTimer;
}

int AudioPlayer::getPosition() const {
    return BASS_ChannelBytes2Seconds(chan, BASS_ChannelGetPosition(chan, BASS_POS_BYTE)) * 1000;
}

int AudioPlayer::getDuration() const {
    return duration;
}

int AudioPlayer::getNotifyInterval() {
    return notifyInterval;
}
void AudioPlayer::setNotifyInterval(signed int milis) {
    notifyInterval = milis;
    if (notifyTimer -> isActive())
        notifyTimer -> setInterval(notifyInterval);
}

void AudioPlayer::setMedia(QUrl mediaPath) {
    mediaUri = mediaPath;
}

void AudioPlayer::setSpectrumBandsCount(int bandsCount) {
    spectrumBandsCount = bandsCount;
}
void AudioPlayer::setSpectrumHeight(int newHeight) {
    spectrumHeight = newHeight;
}

AudioPlayer::MediaState AudioPlayer::state() const {
    return currentState;
}

bool AudioPlayer::isPlayed() const {
    return currentState == PlayingState;
}
bool AudioPlayer::isPaused() const {
    return currentState == PausedState;
}
bool AudioPlayer::isStoped() const {
    return currentState == StoppedState;
}

////////////////////////////////////////////////////////////////////////
/// PRIVATE
////////////////////////////////////////////////////////////////////////

int AudioPlayer::openRemoteChannel(QString path) {
    BASS_ChannelStop(chan);
    chan = BASS_StreamCreateURL(path.toStdWString().c_str(), 0, BASS_SAMPLE_FLOAT, NULL, 0);

//    BASS_Encode_Start(channel, "output.wav", BASS_ENCODE_PCM, NULL, 0);

//    BASS_Encode_StartCAFile(channel, 'mp4f', 'aac ', 0, 128000, "output.mp4"); // only macos
//    BASS_Encode_StartCAFile(channel, 'm4af', 'alac', 0, 0, "output.m4a"); // only macos

    if (!chan) {
        int status = BASS_ErrorGetCode();
        if (status == BASS_ERROR_FILEOPEN)// || status == BASS_ERROR_NONET)
            emit remoteUnprocessed();
        qDebug() << "Can't play stream" <<  BASS_ErrorGetCode() << path.toUtf8();
    }
    return chan;
}

int AudioPlayer::openChannel(QString path) {
    BASS_ChannelStop(chan);
    if (!(chan = BASS_StreamCreateFile(false, path.toStdWString().c_str(), 0, 0, BASS_SAMPLE_FLOAT | BASS_ASYNCFILE)))
//    if (!(stream = BASS_StreamCreateFile(false, path.toStdWString().c_str(), 0, 0, BASS_SAMPLE_LOOP))
//        && !(chan = BASS_MusicLoad(false, path.toStdWString().c_str(), 0, 0, BASS_SAMPLE_LOOP | BASS_MUSIC_RAMP | BASS_MUSIC_POSRESET | BASS_MUSIC_STOPBACK | BASS_STREAM_PRESCAN | BASS_MUSIC_AUTOFREE, 1)))
        qDebug() << "Can't play file " <<  BASS_ErrorGetCode() << path.toUtf8();
    return chan;
}

void AudioPlayer::closeChannel() {
    BASS_ChannelStop(chan);
    BASS_ChannelRemoveSync(chan, syncHandle);
    BASS_StreamFree(chan);
//    BASS_MusicFree(chan);
}

////////////////////////////////////////////////////////////////////////
/// SLOTS
////////////////////////////////////////////////////////////////////////

void AudioPlayer::started() {
    currentState = PlayingState;
    emit stateChanged(PlayingState);
}

void AudioPlayer::stoped() {
    currentState = StoppedState;
}

void AudioPlayer::signalUpdate() {
    int curr_pos = BASS_ChannelBytes2Seconds(chan, BASS_ChannelGetPosition(chan, BASS_POS_BYTE)) * 1000;

    emit positionChanged(curr_pos);
}

void AudioPlayer::calcSpectrum() {
    if (spectrumHeight > 0) {
        if (currentState == StoppedState) {
            QVector<int> l;
            emit spectrumChanged(l.fill(-2, spectrumBandsCount).toList());
        } else
            emit spectrumChanged(getSpectrum());
    }
}

void AudioPlayer::slidePosForward() {
    if (currentState == PlayingState || currentState == PausedState) {
        int dur = getDuration();
        int pos = getPosition() + dur / 10;
        if (pos < dur)
            setPosition(pos);
    }
}
void AudioPlayer::slidePosBackward() {
    if (currentState == PlayingState || currentState == PausedState) {
        int pos = getPosition() - (getDuration() / 10);
        if (pos < 0) pos = 0;
        setPosition(pos);
    }
}

//0 to 10000
void AudioPlayer::setChannelVolume(int val) {
    volumeVal = val > 0 ? (val / 10000.0) : 0;
    BASS_ChannelSetAttribute(chan, BASS_ATTRIB_VOL, volumeVal);
    emit volumeChanged(val);
}

void AudioPlayer::slideVolForward() {
    int newVolLevel = getVolume() + 1000;
    if (newVolLevel > 10000) newVolLevel = 10000;
    setChannelVolume(newVolLevel);
}
void AudioPlayer::slideVolBackward() {
    int newVolLevel = getVolume() - 1000;
    if (newVolLevel < 0) newVolLevel = 0;
    setChannelVolume(newVolLevel);
}

// 0 to 10000
void AudioPlayer::setVolume(int val) {
    BASS_SetConfig(BASS_CONFIG_GVOL_STREAM, val);
    emit volumeChanged(val);
}

float AudioPlayer::getSize() const {
    return size;
}

int AudioPlayer::getVolume() const {
    return volumeVal * 10000;
}

//from 0 to 1
float AudioPlayer::getRemoteFileDownloadPosition() {
    if (size == -1) {
        prevDownloadPos = 0;
        DWORD len = BASS_StreamGetFilePosition(chan, BASS_FILEPOS_END);
        size = len + BASS_StreamGetFilePosition(chan, BASS_FILEPOS_START);
    }

    if (prevDownloadPos != 1) {
        float currDownloadPos = ((BASS_StreamGetFilePosition(chan, BASS_FILEPOS_DOWNLOAD)) / size);
        if (prevDownloadPos == currDownloadPos && currDownloadPos > 0.8)
            prevDownloadPos = 1;
        else
            prevDownloadPos = currDownloadPos;
    }
    return prevDownloadPos;
}

QHash<QString, QString> AudioPlayer::getRemoteFileInfo(QString uri) {
    QHash<QString, QString> ret;

    int chUID = BASS_StreamCreateURL(uri.toStdWString().c_str(), 0, 0, NULL, 0);

    if (!chUID)
        return ret;

    float time = BASS_ChannelBytes2Seconds(chUID, BASS_ChannelGetLength(chUID, BASS_POS_BYTE)); // playback duration
    DWORD len = BASS_StreamGetFilePosition(chUID, BASS_FILEPOS_END); // file length
    int bitrate = (len / (125 * time) + 0.5); // average bitrate (Kbps)

    ret.insert("duration", Duration::fromSeconds(time));

    BASS_CHANNELINFO info;
    if (BASS_ChannelGetInfo(chUID, &info)) {
        int size = len + BASS_StreamGetFilePosition(chUID, BASS_FILEPOS_START);
        ret.insert("info", Format::toInfo(Format::toUnits(size), bitrate, info.freq, info.chans));
    }

    BASS_StreamFree(chUID);

    return ret;
}

float AudioPlayer::getBpmValue(QUrl uri) {
    int cochan;

    if (uri.isLocalFile())
        cochan = BASS_StreamCreateFile(false, uri.toLocalFile().toStdWString().c_str(), 0, 0, BASS_SAMPLE_FLOAT | BASS_STREAM_DECODE | BASS_STREAM_PRESCAN | BASS_SAMPLE_MONO);
    else
        cochan = BASS_StreamCreateURL(uri.toString().toStdWString().c_str(), 0, BASS_SAMPLE_FLOAT | BASS_STREAM_DECODE | BASS_SAMPLE_MONO, NULL, 0);

    if (cochan) {
        int playBackDuration = BASS_ChannelBytes2Seconds(cochan, BASS_ChannelGetLength(cochan, BASS_POS_BYTE));
        BASS_ChannelSetAttribute(cochan, BASS_ATTRIB_VOL, 0);
        qDebug() << playBackDuration;
        return BASS_FX_BPM_DecodeGet(cochan,
                              0,
                              60,
                              0, //MAKEWORD(60, 230),
                              BASS_FX_FREESOURCE, //BASS_FX_BPM_BKGRND // BASS_FX_BPM_MULT2
                              NULL, NULL);

//        float last = BASS_FX_BPM_DecodeGet(cochan,
//                              0.0,
//                              playBackDuration,
//                              MAKELONG(85, 90),
//                              BASS_FX_FREESOURCE, //BASS_FX_BPM_BKGRND // BASS_FX_BPM_MULT2
//                              NULL, NULL);

//        qDebug() << last << " " << first;
    } else return 0;
}

QList<int> AudioPlayer::getSpectrum() {
    float fft[1024];
    BASS_ChannelGetData(chan, fft, BASS_DATA_FFT2048);
    QList<int> res;

    int b0 = 0, x, y;

    for (x = 0; x < spectrumBandsCount; x++) {
        float peak = 0;
        int b1 = qPow(2, x * 10.0 / (spectrumBandsCount - 1));
        if (b1 > 1023) b1 = 1023;
        if (b1 <= b0) b1 = b0 + 1; // make sure it uses at least 1 FFT bin
        for (; b0 < b1; b0++)
            if (peak < fft[1 + b0])
                peak = fft[1 + b0];

        y = qSqrt(peak) * 3 * spectrumHeight - 4; // scale it (sqrt to make low values more visible)
        if (y > spectrumHeight) y = spectrumHeight; // cap it

        res.append(y);
    }

    return res;
}

////////////////////////////////////////////////////////////////////////

void AudioPlayer::play() {
    if (currentState == PausedState) {
        resume();
    } else {
        closeChannel();
        if (mediaUri.isEmpty()) {
            emit mediaStatusChanged(NoMedia);
        } else {
            qDebug() << mediaUri.toString();

            if (mediaUri.isLocalFile()) {
                openChannel(mediaUri.toLocalFile());
                size = 0;
                prevDownloadPos = 1;
            } else {
                openRemoteChannel(mediaUri.toString());
                size = -1;
            }

            if (chan) {
                BASS_ChannelSetAttribute(chan, BASS_ATTRIB_VOL, volumeVal);
                duration = BASS_ChannelBytes2Seconds(chan, BASS_ChannelGetLength(chan, BASS_POS_BYTE)) * 1000;
                durationChanged(duration);
                BASS_ChannelPlay(chan, true);
                notifyTimer -> start(notifyInterval);
                //TODO: remove sync and check end of file by timer
                syncHandle = BASS_ChannelSetSync(chan, BASS_SYNC_END, 0, &endTrackSync, this);
//                BASS_SYNC_DOWNLOAD
            } else {
                qDebug() << "Can't play file";
            }
        }
    }
}

void AudioPlayer::pause() {
    notifyTimer -> stop();
    BASS_ChannelPause(chan);
    emit stateChanged(PausedState);
    currentState = PausedState;
}

void AudioPlayer::resume() {
    if (!BASS_ChannelPlay(chan, false)) {
        emit mediaStatusChanged(StalledMedia);
        qDebug() << "Error resuming";
    } else {
        notifyTimer -> start(notifyInterval);
    }
}

void AudioPlayer::stop() {
    closeChannel();
    notifyTimer -> stop();
    emit stateChanged(StoppedState);
}

void AudioPlayer::endOfPlayback() {
    stop();
    closeChannel();
    emit mediaStatusChanged(EndOfMedia);
}

void AudioPlayer::setPosition(int position) {
    BASS_ChannelSetPosition(chan, BASS_ChannelSeconds2Bytes(chan, position / 1000.0), BASS_POS_BYTE);
}
<|endoftext|>