<commit_before>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you 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 <sys/types.h>
#include <unistd.h>

#include <string>

#include <glog/logging.h>
#include <gtest/gtest.h>

#include "kudu/integration-tests/external_mini_cluster.h"
#include "kudu/gutil/stl_util.h"
#include "kudu/gutil/strings/substitute.h"
#include "kudu/gutil/strings/util.h"
#include "kudu/security/test/mini_kdc.h"
#include "kudu/util/metrics.h"
#include "kudu/util/net/net_util.h"
#include "kudu/util/test_util.h"

METRIC_DECLARE_entity(server);
METRIC_DECLARE_gauge_uint64(threads_running);

namespace kudu {

using std::string;
using strings::Substitute;

enum KerberosMode {
  WITHOUT_KERBEROS, WITH_KERBEROS
};

class ExternalMiniClusterTest : public KuduTest,
                                public testing::WithParamInterface<KerberosMode> {};

INSTANTIATE_TEST_CASE_P(KerberosOnAndOff,
                        ExternalMiniClusterTest,
                        ::testing::Values(WITHOUT_KERBEROS, WITH_KERBEROS));

void SmokeTestKerberizedCluster(const ExternalMiniClusterOptions& opts) {
  ASSERT_TRUE(opts.enable_kerberos);

  ExternalMiniCluster cluster(opts);
  ASSERT_OK(cluster.Start());

  // Sleep long enough to ensure that the tserver's ticket would have expired
  // if not for the renewal thread doing its thing.
  SleepFor(MonoDelta::FromSeconds(10));

  // Re-kinit for the client, since the client's ticket would have expired as well.
  ASSERT_OK(cluster.kdc()->Kinit("test-admin"));

  // Restart the master, and make sure the tserver is still able to reconnect and
  // authenticate.
  cluster.master(0)->Shutdown();
  ASSERT_OK(cluster.master(0)->Restart());
  // Ensure that all of the tablet servers can register with the masters.
  ASSERT_OK(cluster.WaitForTabletServerCount(opts.num_tablet_servers, MonoDelta::FromSeconds(30)));
  cluster.Shutdown();
}

TEST_F(ExternalMiniClusterTest, TestKerberosRenewal) {
  ExternalMiniClusterOptions opts;
  opts.enable_kerberos = true;
  // Set the kerberos ticket lifetime as 5 seconds to force ticket renewal every 5 seconds.
  opts.mini_kdc_options.ticket_lifetime = "5s";
  opts.num_tablet_servers = 1;

  SmokeTestKerberizedCluster(opts);
}

TEST_F(ExternalMiniClusterTest, TestKerberosReacquire) {
  ExternalMiniClusterOptions opts;
  opts.enable_kerberos = true;
  // Set the kerberos ticket lifetime and the renew lifetime as 5 seconds each, to force the
  // processes to acquire a new ticket instead of being able to renew the existing one.
  opts.mini_kdc_options.ticket_lifetime = "5s";
  opts.mini_kdc_options.renew_lifetime = "5s";
  opts.num_tablet_servers = 1;

  SmokeTestKerberizedCluster(opts);
}

TEST_P(ExternalMiniClusterTest, TestBasicOperation) {
  ExternalMiniClusterOptions opts;
  opts.enable_kerberos = GetParam() == WITH_KERBEROS;

  // Hard-coded RPC ports for the masters. This is safe, as this unit test
  // runs under a resource lock (see CMakeLists.txt in this directory).
  // TODO we should have a generic method to obtain n free ports.
  opts.master_rpc_ports = { 11010, 11011, 11012 };
  opts.num_masters = opts.master_rpc_ports.size();
  opts.num_tablet_servers = 3;

  ExternalMiniCluster cluster(opts);
  ASSERT_OK(cluster.Start());

  // Verify each of the masters.
  for (int i = 0; i < opts.num_masters; i++) {
    SCOPED_TRACE(i);
    ExternalMaster* master = CHECK_NOTNULL(cluster.master(i));
    HostPort master_rpc = master->bound_rpc_hostport();
    EXPECT_TRUE(HasPrefixString(master_rpc.ToString(), "127.0.0.1:")) << master_rpc.ToString();

    HostPort master_http = master->bound_http_hostport();
    EXPECT_TRUE(HasPrefixString(master_http.ToString(), "127.0.0.1:")) << master_http.ToString();

    // Retrieve a thread metric, which should always be present on any master.
    int64_t value;
    ASSERT_OK(master->GetInt64Metric(&METRIC_ENTITY_server,
                                     "kudu.master",
                                     &METRIC_threads_running,
                                     "value",
                                     &value));
    EXPECT_GT(value, 0);
  }

  // Verify each of the tablet servers.
  for (int i = 0; i < opts.num_tablet_servers; i++) {
    SCOPED_TRACE(i);
    ExternalTabletServer* ts = CHECK_NOTNULL(cluster.tablet_server(i));
    HostPort ts_rpc = ts->bound_rpc_hostport();
    string expected_prefix = Substitute("$0:", cluster.GetBindIpForTabletServer(i));
    EXPECT_NE(expected_prefix, "127.0.0.1") << "Should bind to unique per-server hosts";
    EXPECT_TRUE(HasPrefixString(ts_rpc.ToString(), expected_prefix)) << ts_rpc.ToString();

    HostPort ts_http = ts->bound_http_hostport();
    EXPECT_TRUE(HasPrefixString(ts_http.ToString(), expected_prefix)) << ts_http.ToString();

    // Retrieve a thread metric, which should always be present on any TS.
    int64_t value;
    ASSERT_OK(ts->GetInt64Metric(&METRIC_ENTITY_server,
                                 "kudu.tabletserver",
                                 &METRIC_threads_running,
                                 "value",
                                 &value));
    EXPECT_GT(value, 0);
  }

  // Ensure that all of the tablet servers can register with the masters.
  ASSERT_OK(cluster.WaitForTabletServerCount(opts.num_tablet_servers, MonoDelta::FromSeconds(30)));

  // Restart a master and a tablet server. Make sure they come back up with the same ports.
  ExternalMaster* master = cluster.master(0);
  HostPort master_rpc = master->bound_rpc_hostport();
  HostPort master_http = master->bound_http_hostport();

  master->Shutdown();
  ASSERT_OK(master->Restart());

  ASSERT_EQ(master_rpc.ToString(), master->bound_rpc_hostport().ToString());
  ASSERT_EQ(master_http.ToString(), master->bound_http_hostport().ToString());

  ExternalTabletServer* ts = cluster.tablet_server(0);

  HostPort ts_rpc = ts->bound_rpc_hostport();
  HostPort ts_http = ts->bound_http_hostport();

  ts->Shutdown();
  ASSERT_OK(ts->Restart());

  ASSERT_EQ(ts_rpc.ToString(), ts->bound_rpc_hostport().ToString());
  ASSERT_EQ(ts_http.ToString(), ts->bound_http_hostport().ToString());

  // Verify that, in a Kerberized cluster, if we drop our Kerberos environment,
  // we can't make RPCs to a server.
  if (opts.enable_kerberos) {
    ASSERT_OK(cluster.kdc()->Kdestroy());
    Status s = cluster.SetFlag(ts, "foo", "bar");
    // The error differs depending on the version of Kerberos, so we match
    // either message.
    ASSERT_STR_MATCHES(s.ToString(), "Not authorized.*"
                       "(Credentials cache file.*not found|"
                        "No Kerberos credentials|"
                        ".*No such file or directory)");
  }
  cluster.Shutdown();
}

} // namespace kudu
<commit_msg>Fix TestKerberosRenewal/Reacquire flakiness<commit_after>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you 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 <sys/types.h>
#include <unistd.h>

#include <string>

#include <glog/logging.h>
#include <gtest/gtest.h>

#include "kudu/integration-tests/external_mini_cluster.h"
#include "kudu/gutil/stl_util.h"
#include "kudu/gutil/strings/substitute.h"
#include "kudu/gutil/strings/util.h"
#include "kudu/security/test/mini_kdc.h"
#include "kudu/util/metrics.h"
#include "kudu/util/net/net_util.h"
#include "kudu/util/test_util.h"

METRIC_DECLARE_entity(server);
METRIC_DECLARE_gauge_uint64(threads_running);

namespace kudu {

using std::string;
using strings::Substitute;

enum KerberosMode {
  WITHOUT_KERBEROS, WITH_KERBEROS
};

class ExternalMiniClusterTest : public KuduTest,
                                public testing::WithParamInterface<KerberosMode> {};

INSTANTIATE_TEST_CASE_P(KerberosOnAndOff,
                        ExternalMiniClusterTest,
                        ::testing::Values(WITHOUT_KERBEROS, WITH_KERBEROS));

void SmokeTestKerberizedCluster(const ExternalMiniClusterOptions& opts) {
  ASSERT_TRUE(opts.enable_kerberos);

  ExternalMiniCluster cluster(opts);
  ASSERT_OK(cluster.Start());

  // Sleep long enough to ensure that the tserver's ticket would have expired
  // if not for the renewal thread doing its thing.
  SleepFor(MonoDelta::FromSeconds(16));

  // Re-kinit for the client, since the client's ticket would have expired as well
  // since the renewal thread doesn't run for the test client.
  ASSERT_OK(cluster.kdc()->Kinit("test-admin"));

  // Restart the master, and make sure the tserver is still able to reconnect and
  // authenticate.
  cluster.master(0)->Shutdown();
  ASSERT_OK(cluster.master(0)->Restart());
  // Ensure that all of the tablet servers can register with the masters.
  ASSERT_OK(cluster.WaitForTabletServerCount(opts.num_tablet_servers, MonoDelta::FromSeconds(30)));
  cluster.Shutdown();
}

TEST_F(ExternalMiniClusterTest, TestKerberosRenewal) {
  if (!AllowSlowTests()) return;

  ExternalMiniClusterOptions opts;
  opts.enable_kerberos = true;
  // Set the kerberos ticket lifetime as 5 seconds to force ticket renewal every 5 seconds.
  opts.mini_kdc_options.ticket_lifetime = "15s";
  opts.num_tablet_servers = 1;

  SmokeTestKerberizedCluster(opts);
}

TEST_F(ExternalMiniClusterTest, TestKerberosReacquire) {
  if (!AllowSlowTests()) return;

  ExternalMiniClusterOptions opts;
  opts.enable_kerberos = true;
  // Set the kerberos ticket lifetime and the renew lifetime as 5 seconds each, to force the
  // processes to acquire a new ticket instead of being able to renew the existing one.
  opts.mini_kdc_options.ticket_lifetime = "15s";
  opts.mini_kdc_options.renew_lifetime = "15s";
  opts.num_tablet_servers = 1;

  SmokeTestKerberizedCluster(opts);
}

TEST_P(ExternalMiniClusterTest, TestBasicOperation) {
  ExternalMiniClusterOptions opts;
  opts.enable_kerberos = GetParam() == WITH_KERBEROS;

  // Hard-coded RPC ports for the masters. This is safe, as this unit test
  // runs under a resource lock (see CMakeLists.txt in this directory).
  // TODO we should have a generic method to obtain n free ports.
  opts.master_rpc_ports = { 11010, 11011, 11012 };
  opts.num_masters = opts.master_rpc_ports.size();
  opts.num_tablet_servers = 3;

  ExternalMiniCluster cluster(opts);
  ASSERT_OK(cluster.Start());

  // Verify each of the masters.
  for (int i = 0; i < opts.num_masters; i++) {
    SCOPED_TRACE(i);
    ExternalMaster* master = CHECK_NOTNULL(cluster.master(i));
    HostPort master_rpc = master->bound_rpc_hostport();
    EXPECT_TRUE(HasPrefixString(master_rpc.ToString(), "127.0.0.1:")) << master_rpc.ToString();

    HostPort master_http = master->bound_http_hostport();
    EXPECT_TRUE(HasPrefixString(master_http.ToString(), "127.0.0.1:")) << master_http.ToString();

    // Retrieve a thread metric, which should always be present on any master.
    int64_t value;
    ASSERT_OK(master->GetInt64Metric(&METRIC_ENTITY_server,
                                     "kudu.master",
                                     &METRIC_threads_running,
                                     "value",
                                     &value));
    EXPECT_GT(value, 0);
  }

  // Verify each of the tablet servers.
  for (int i = 0; i < opts.num_tablet_servers; i++) {
    SCOPED_TRACE(i);
    ExternalTabletServer* ts = CHECK_NOTNULL(cluster.tablet_server(i));
    HostPort ts_rpc = ts->bound_rpc_hostport();
    string expected_prefix = Substitute("$0:", cluster.GetBindIpForTabletServer(i));
    EXPECT_NE(expected_prefix, "127.0.0.1") << "Should bind to unique per-server hosts";
    EXPECT_TRUE(HasPrefixString(ts_rpc.ToString(), expected_prefix)) << ts_rpc.ToString();

    HostPort ts_http = ts->bound_http_hostport();
    EXPECT_TRUE(HasPrefixString(ts_http.ToString(), expected_prefix)) << ts_http.ToString();

    // Retrieve a thread metric, which should always be present on any TS.
    int64_t value;
    ASSERT_OK(ts->GetInt64Metric(&METRIC_ENTITY_server,
                                 "kudu.tabletserver",
                                 &METRIC_threads_running,
                                 "value",
                                 &value));
    EXPECT_GT(value, 0);
  }

  // Ensure that all of the tablet servers can register with the masters.
  ASSERT_OK(cluster.WaitForTabletServerCount(opts.num_tablet_servers, MonoDelta::FromSeconds(30)));

  // Restart a master and a tablet server. Make sure they come back up with the same ports.
  ExternalMaster* master = cluster.master(0);
  HostPort master_rpc = master->bound_rpc_hostport();
  HostPort master_http = master->bound_http_hostport();

  master->Shutdown();
  ASSERT_OK(master->Restart());

  ASSERT_EQ(master_rpc.ToString(), master->bound_rpc_hostport().ToString());
  ASSERT_EQ(master_http.ToString(), master->bound_http_hostport().ToString());

  ExternalTabletServer* ts = cluster.tablet_server(0);

  HostPort ts_rpc = ts->bound_rpc_hostport();
  HostPort ts_http = ts->bound_http_hostport();

  ts->Shutdown();
  ASSERT_OK(ts->Restart());

  ASSERT_EQ(ts_rpc.ToString(), ts->bound_rpc_hostport().ToString());
  ASSERT_EQ(ts_http.ToString(), ts->bound_http_hostport().ToString());

  // Verify that, in a Kerberized cluster, if we drop our Kerberos environment,
  // we can't make RPCs to a server.
  if (opts.enable_kerberos) {
    ASSERT_OK(cluster.kdc()->Kdestroy());
    Status s = cluster.SetFlag(ts, "foo", "bar");
    // The error differs depending on the version of Kerberos, so we match
    // either message.
    ASSERT_STR_MATCHES(s.ToString(), "Not authorized.*"
                       "(Credentials cache file.*not found|"
                        "No Kerberos credentials|"
                        ".*No such file or directory)");
  }
  cluster.Shutdown();
}

} // namespace kudu
<|endoftext|>


<commit_before>#ifdef _WIN32
#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
#endif

#include <iostream>
#include <fstream>
#include <cctype>
#include <algorithm>
#include <sys/stat.h>
#include "file.hpp"
#include "context.hpp"
#include "sass2scss/sass2scss.h"

namespace Sass {
  namespace File {
    using namespace std;

    size_t find_last_folder_separator(const string& path, size_t limit = string::npos)
    {
      size_t pos = string::npos;
      size_t pos_p = path.find_last_of('/', limit);
      size_t pos_w = string::npos;
      #ifdef _WIN32
      pos_w = path.find_last_of('\\', limit);
      #endif
      if (pos_p != string::npos && pos_w != string::npos) {
        pos = max(pos_p, pos_w);
      }
      else if (pos_p != string::npos) {
        pos = pos_p;
      }
      else {
        pos = pos_w;
      }
      return pos;
    }

    string base_name(string path)
    {
      size_t pos = find_last_folder_separator(path);
      if (pos == string::npos) return path;
      else                     return path.substr(pos+1);
    }

    string dir_name(string path)
    {
      size_t pos = find_last_folder_separator(path);
      if (pos == string::npos) return "";
      else                     return path.substr(0, pos+1);
    }

    string join_paths(string l, string r)
    {
      if (l.empty()) return r;
      if (r.empty()) return l;
      if (is_absolute_path(r)) return r;

      if (l[l.length()-1] != '/') l += '/';

      while ((r.length() > 3) && ((r.substr(0, 3) == "../") || (r.substr(0, 3)) == "..\\")) {
        r = r.substr(3);
        size_t pos = find_last_folder_separator(l, l.length() - 2);
        l = l.substr(0, pos == string::npos ? pos : pos + 1);
      }

      return l + r;
    }

    bool is_absolute_path(const string& path)
    {
      if (path[0] == '/') return true;
      // TODO: UN-HACKIFY THIS
      #ifdef _WIN32
      if (path.length() >= 2 && isalpha(path[0]) && path[1] == ':') return true;
      #endif
      return false;
    }

    string make_absolute_path(const string& path, const string& cwd)
    {
      return (is_absolute_path(path) ? path : join_paths(cwd, path));
    }

    string resolve_relative_path(const string& uri, const string& base, const string& cwd)
    {
      string absolute_uri = make_absolute_path(uri, cwd);
      string absolute_base = make_absolute_path(base, cwd);

      string stripped_uri = "";
      string stripped_base = "";

      size_t index = 0;
      size_t minSize = min(absolute_uri.size(), absolute_base.size());
      for (size_t i = 0; i < minSize; ++i) {
        if (absolute_uri[i] != absolute_base[i]) break;
        if (absolute_uri[i] == '/') index = i + 1;
      }
      for (size_t i = index; i < absolute_uri.size(); ++i) {
        stripped_uri += absolute_uri[i];
      }
      for (size_t i = index; i < absolute_base.size(); ++i) {
        stripped_base += absolute_base[i];
      }
      size_t directories = 0;
      for (size_t i = 0; i < stripped_base.size(); ++i) {
        if (stripped_base[i] == '/') ++directories;
      }
      string result = "";
      for (size_t i = 0; i < directories; ++i) {
        result += "../";
      }
      result += stripped_uri;

      return result;
    }

    char* resolve_and_load(string path, string& real_path)
    {
      // Resolution order for ambiguous imports:
      // (1) filename as given
      // (2) underscore + given
      // (3) underscore + given + extension
      // (4) given + extension
      char* contents = 0;
      real_path = path;
      // if the file isn't found with the given filename ...
      if (!(contents = read_file(real_path))) {
        string dir(dir_name(path));
        string base(base_name(path));
        string _base("_" + base);
        real_path = dir + _base;
        // if the file isn't found with '_' + filename ...
        if (!(contents = read_file(real_path))) {
          string _base_scss(_base + ".scss");
          real_path = dir + _base_scss;
          // if the file isn't found with '_' + filename + ".scss" ...
          if (!(contents = read_file(real_path))) {
            string base_scss(base + ".scss");
            // try filename + ".scss" as the last resort
            real_path = dir + base_scss;
            contents = read_file(real_path);
          }
        }
      }
      return contents;
    }

    char* read_file(string path)
    {
      struct stat st;
      if (stat(path.c_str(), &st) == -1 || S_ISDIR(st.st_mode)) return 0;
      ifstream file(path.c_str(), ios::in | ios::binary | ios::ate);
      string extension;
      if (path.length() > 5) {
        extension = path.substr(path.length() - 5, 5);
      }
      char* contents = 0;
      if (file.is_open()) {
        size_t size = file.tellg();
        contents = new char[size + 1]; // extra byte for the null char
        file.seekg(0, ios::beg);
        file.read(contents, size);
        contents[size] = '\0';
        file.close();
      }
      if (extension == ".sass") {
        return ocbnet::sass2scss(contents, SASS2SCSS_PRETTIFY_1);
      } else {
        return contents;
      }
    }

  }
}
<commit_msg>Fixes memory leak<commit_after>#ifdef _WIN32
#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
#endif

#include <iostream>
#include <fstream>
#include <cctype>
#include <algorithm>
#include <sys/stat.h>
#include "file.hpp"
#include "context.hpp"
#include "sass2scss/sass2scss.h"

namespace Sass {
  namespace File {
    using namespace std;

    size_t find_last_folder_separator(const string& path, size_t limit = string::npos)
    {
      size_t pos = string::npos;
      size_t pos_p = path.find_last_of('/', limit);
      size_t pos_w = string::npos;
      #ifdef _WIN32
      pos_w = path.find_last_of('\\', limit);
      #endif
      if (pos_p != string::npos && pos_w != string::npos) {
        pos = max(pos_p, pos_w);
      }
      else if (pos_p != string::npos) {
        pos = pos_p;
      }
      else {
        pos = pos_w;
      }
      return pos;
    }

    string base_name(string path)
    {
      size_t pos = find_last_folder_separator(path);
      if (pos == string::npos) return path;
      else                     return path.substr(pos+1);
    }

    string dir_name(string path)
    {
      size_t pos = find_last_folder_separator(path);
      if (pos == string::npos) return "";
      else                     return path.substr(0, pos+1);
    }

    string join_paths(string l, string r)
    {
      if (l.empty()) return r;
      if (r.empty()) return l;
      if (is_absolute_path(r)) return r;

      if (l[l.length()-1] != '/') l += '/';

      while ((r.length() > 3) && ((r.substr(0, 3) == "../") || (r.substr(0, 3)) == "..\\")) {
        r = r.substr(3);
        size_t pos = find_last_folder_separator(l, l.length() - 2);
        l = l.substr(0, pos == string::npos ? pos : pos + 1);
      }

      return l + r;
    }

    bool is_absolute_path(const string& path)
    {
      if (path[0] == '/') return true;
      // TODO: UN-HACKIFY THIS
      #ifdef _WIN32
      if (path.length() >= 2 && isalpha(path[0]) && path[1] == ':') return true;
      #endif
      return false;
    }

    string make_absolute_path(const string& path, const string& cwd)
    {
      return (is_absolute_path(path) ? path : join_paths(cwd, path));
    }

    string resolve_relative_path(const string& uri, const string& base, const string& cwd)
    {
      string absolute_uri = make_absolute_path(uri, cwd);
      string absolute_base = make_absolute_path(base, cwd);

      string stripped_uri = "";
      string stripped_base = "";

      size_t index = 0;
      size_t minSize = min(absolute_uri.size(), absolute_base.size());
      for (size_t i = 0; i < minSize; ++i) {
        if (absolute_uri[i] != absolute_base[i]) break;
        if (absolute_uri[i] == '/') index = i + 1;
      }
      for (size_t i = index; i < absolute_uri.size(); ++i) {
        stripped_uri += absolute_uri[i];
      }
      for (size_t i = index; i < absolute_base.size(); ++i) {
        stripped_base += absolute_base[i];
      }
      size_t directories = 0;
      for (size_t i = 0; i < stripped_base.size(); ++i) {
        if (stripped_base[i] == '/') ++directories;
      }
      string result = "";
      for (size_t i = 0; i < directories; ++i) {
        result += "../";
      }
      result += stripped_uri;

      return result;
    }

    char* resolve_and_load(string path, string& real_path)
    {
      // Resolution order for ambiguous imports:
      // (1) filename as given
      // (2) underscore + given
      // (3) underscore + given + extension
      // (4) given + extension
      char* contents = 0;
      real_path = path;
      // if the file isn't found with the given filename ...
      if (!(contents = read_file(real_path))) {
        string dir(dir_name(path));
        string base(base_name(path));
        string _base("_" + base);
        real_path = dir + _base;
        // if the file isn't found with '_' + filename ...
        if (!(contents = read_file(real_path))) {
          string _base_scss(_base + ".scss");
          real_path = dir + _base_scss;
          // if the file isn't found with '_' + filename + ".scss" ...
          if (!(contents = read_file(real_path))) {
            string base_scss(base + ".scss");
            // try filename + ".scss" as the last resort
            real_path = dir + base_scss;
            contents = read_file(real_path);
          }
        }
      }
      return contents;
    }

    char* read_file(string path)
    {
      struct stat st;
      if (stat(path.c_str(), &st) == -1 || S_ISDIR(st.st_mode)) return 0;
      ifstream file(path.c_str(), ios::in | ios::binary | ios::ate);
      string extension;
      if (path.length() > 5) {
        extension = path.substr(path.length() - 5, 5);
      }
      char* contents = 0;
      if (file.is_open()) {
        size_t size = file.tellg();
        contents = new char[size + 1]; // extra byte for the null char
        file.seekg(0, ios::beg);
        file.read(contents, size);
        contents[size] = '\0';
        file.close();
      }
      if (extension == ".sass") {
        char * converted = ocbnet::sass2scss(contents, SASS2SCSS_PRETTIFY_1);
        delete[] contents; // free the sass content
        return converted; // should be freed by caller
      } else {
        return contents;
      }
    }

  }
}
<|endoftext|>


<commit_before>// Copyright 2014 Toggl Desktop developers.

#include "./https_client.h"

#include <string>
#include <sstream>

#include "Poco/Exception.h"
#include "Poco/InflatingStream.h"
#include "Poco/DeflatingStream.h"
#include "Poco/Logger.h"
#include "Poco/URI.h"
#include "Poco/NumberParser.h"
#include "Poco/Net/Context.h"
#include "Poco/Net/NameValueCollection.h"
#include "Poco/Net/HTTPMessage.h"
#include "Poco/Net/HTTPBasicCredentials.h"
#include "Poco/Net/InvalidCertificateHandler.h"
#include "Poco/Net/AcceptCertificateHandler.h"
#include "Poco/Net/SSLManager.h"
#include "Poco/Net/PrivateKeyPassphraseHandler.h"
#include "Poco/Net/SecureStreamSocket.h"

#include "./libjson.h"
#include "./const.h"

namespace kopsik {

std::string HTTPSClient::AppName = std::string("");
std::string HTTPSClient::AppVersion = std::string("");
std::string HTTPSClient::APIURL = std::string(kAPIURL);
bool HTTPSClient::UseProxy = false;
bool HTTPSClient::IgnoreCert = false;
kopsik::Proxy HTTPSClient::ProxySettings = Proxy();

error HTTPSClient::PostJSON(
    const std::string relative_url,
    const std::string json,
    const std::string basic_auth_username,
    const std::string basic_auth_password,
    std::string *response_body) {
    return requestJSON(Poco::Net::HTTPRequest::HTTP_POST,
                       relative_url,
                       json,
                       basic_auth_username,
                       basic_auth_password,
                       response_body);
}

error HTTPSClient::GetJSON(
    const std::string relative_url,
    const std::string basic_auth_username,
    const std::string basic_auth_password,
    std::string *response_body) {
    return requestJSON(Poco::Net::HTTPRequest::HTTP_GET,
                       relative_url,
                       "",
                       basic_auth_username,
                       basic_auth_password,
                       response_body);
}

error HTTPSClient::requestJSON(
    const std::string method,
    const std::string relative_url,
    const std::string json,
    const std::string basic_auth_username,
    const std::string basic_auth_password,
    std::string *response_body) {
    return request(
        method,
        relative_url,
        json,
        basic_auth_username,
        basic_auth_password,
        response_body);
}

error HTTPSClient::request(
    const std::string method,
    const std::string relative_url,
    const std::string payload,
    const std::string basic_auth_username,
    const std::string basic_auth_password,
    std::string *response_body) {

    poco_assert(!method.empty());
    poco_assert(!relative_url.empty());

    poco_check_ptr(response_body);

    *response_body = "";

    try {
        Poco::URI uri(APIURL);

        Poco::SharedPtr<Poco::Net::InvalidCertificateHandler>
        acceptCertHandler =
            new Poco::Net::AcceptCertificateHandler(true);

        Poco::Net::Context::VerificationMode verification_mode =
            Poco::Net::Context::VERIFY_RELAXED;
        if (IgnoreCert) {
            verification_mode = Poco::Net::Context::VERIFY_NONE;
        }
        Poco::Net::Context::Ptr context = new Poco::Net::Context(
            Poco::Net::Context::CLIENT_USE, "",
            verification_mode, 9, true, "ALL");

        Poco::Net::SSLManager::instance().initializeClient(
            0, acceptCertHandler, context);

        Poco::Net::HTTPSClientSession session(uri.getHost(), uri.getPort(),
                                              context);
        if (ProxySettings.IsConfigured()) {
            session.setProxy(ProxySettings.host, ProxySettings.port);
            if (ProxySettings.HasCredentials()) {
                session.setProxyCredentials(ProxySettings.username,
                                            ProxySettings.password);
            }
        }
        session.setKeepAlive(false);
        session.setTimeout(Poco::Timespan(10 * Poco::Timespan::SECONDS));

        Poco::Logger &logger = Poco::Logger::get("https_client");
        {
            std::stringstream ss;
            ss << "Sending request to " << relative_url << " ..";
            logger.debug(ss.str());
        }

        std::string encoded_url("");
        Poco::URI::encode(relative_url, "", encoded_url);
        Poco::Net::HTTPRequest req(method,
                                   encoded_url,
                                   Poco::Net::HTTPMessage::HTTP_1_1);
        req.setKeepAlive(false);
        req.setContentType("application/json");
        req.set("User-Agent", UserAgent());
        req.setChunkedTransferEncoding(true);

        Poco::Net::HTTPBasicCredentials cred(
            basic_auth_username, basic_auth_password);
        if (!basic_auth_username.empty() && !basic_auth_password.empty()) {
            cred.authenticate(req);
        }

        std::istringstream requestStream(payload);
        Poco::DeflatingInputStream gzipRequest(
            requestStream,
            Poco::DeflatingStreamBuf::STREAM_GZIP);
        Poco::DeflatingStreamBuf *pBuff = gzipRequest.rdbuf();

        Poco::Int64 size = pBuff->pubseekoff(0, std::ios::end, std::ios::in);
        pBuff->pubseekpos(0, std::ios::in);

        req.setContentLength(size);
        req.set("Content-Encoding", "gzip");
        req.set("Accept-Encoding", "gzip");

        session.sendRequest(req) << pBuff << std::flush;

        // Log out request contents
        std::stringstream request_string;
        req.write(request_string);
        logger.debug(request_string.str());

        logger.debug("Request sent. Receiving response..");

        // Receive response
        Poco::Net::HTTPResponse response;
        std::istream& is = session.receiveResponse(response);

        {
            std::stringstream ss;
            ss << "Response status code " << response.getStatus()
               << ", content length " << response.getContentLength()
               << ", content type " << response.getContentType();
            if (response.has("Content-Encoding")) {
                ss << ", content encoding " << response.get("Content-Encoding");
            } else {
                ss << ", unknown content encoding";
            }
            logger.debug(ss.str());
        }

        // Inflate, if gzip was sent
        if (response.has("Content-Encoding") &&
                "gzip" == response.get("Content-Encoding")) {
            Poco::InflatingInputStream inflater(
                is,
                Poco::InflatingStreamBuf::STREAM_GZIP);
            {
                std::stringstream ss;
                ss << inflater.rdbuf();
                *response_body = ss.str();
            }
        } else {
            std::istreambuf_iterator<char> eos;
            *response_body =
                std::string(std::istreambuf_iterator<char>(is), eos);
        }

        logger.trace(*response_body);

        if (response.getStatus() < 200 || response.getStatus() >= 300) {
            if (response_body->empty()) {
                std::stringstream description;
                description << "Request to server failed with status code: "
                            << response.getStatus();
                return description.str();
            }
            return "Request failed with error: " + *response_body;
        }
    } catch(const Poco::Exception& exc) {
        return exc.displayText();
    } catch(const std::exception& ex) {
        return ex.what();
    } catch(const std::string& ex) {
        return ex;
    }
    return noError;
}

}   // namespace kopsik
<commit_msg>Debug http response text encoding<commit_after>// Copyright 2014 Toggl Desktop developers.

#include "./https_client.h"

#include <string>
#include <sstream>

#include "Poco/Exception.h"
#include "Poco/InflatingStream.h"
#include "Poco/DeflatingStream.h"
#include "Poco/Logger.h"
#include "Poco/URI.h"
#include "Poco/NumberParser.h"
#include "Poco/Net/Context.h"
#include "Poco/Net/NameValueCollection.h"
#include "Poco/Net/HTTPMessage.h"
#include "Poco/Net/HTTPBasicCredentials.h"
#include "Poco/Net/InvalidCertificateHandler.h"
#include "Poco/Net/AcceptCertificateHandler.h"
#include "Poco/Net/SSLManager.h"
#include "Poco/Net/PrivateKeyPassphraseHandler.h"
#include "Poco/Net/SecureStreamSocket.h"
#include "Poco/TextEncoding.h"
#include "Poco/UTF8Encoding.h"

#include "./libjson.h"
#include "./const.h"

namespace kopsik {

std::string HTTPSClient::AppName = std::string("");
std::string HTTPSClient::AppVersion = std::string("");
std::string HTTPSClient::APIURL = std::string(kAPIURL);
bool HTTPSClient::UseProxy = false;
bool HTTPSClient::IgnoreCert = false;
kopsik::Proxy HTTPSClient::ProxySettings = Proxy();

error HTTPSClient::PostJSON(
    const std::string relative_url,
    const std::string json,
    const std::string basic_auth_username,
    const std::string basic_auth_password,
    std::string *response_body) {
    return requestJSON(Poco::Net::HTTPRequest::HTTP_POST,
                       relative_url,
                       json,
                       basic_auth_username,
                       basic_auth_password,
                       response_body);
}

error HTTPSClient::GetJSON(
    const std::string relative_url,
    const std::string basic_auth_username,
    const std::string basic_auth_password,
    std::string *response_body) {
    return requestJSON(Poco::Net::HTTPRequest::HTTP_GET,
                       relative_url,
                       "",
                       basic_auth_username,
                       basic_auth_password,
                       response_body);
}

error HTTPSClient::requestJSON(
    const std::string method,
    const std::string relative_url,
    const std::string json,
    const std::string basic_auth_username,
    const std::string basic_auth_password,
    std::string *response_body) {
    return request(
        method,
        relative_url,
        json,
        basic_auth_username,
        basic_auth_password,
        response_body);
}

error HTTPSClient::request(
    const std::string method,
    const std::string relative_url,
    const std::string payload,
    const std::string basic_auth_username,
    const std::string basic_auth_password,
    std::string *response_body) {

    poco_assert(!method.empty());
    poco_assert(!relative_url.empty());

    poco_check_ptr(response_body);

    *response_body = "";

    try {
        Poco::URI uri(APIURL);

        Poco::SharedPtr<Poco::Net::InvalidCertificateHandler>
        acceptCertHandler =
            new Poco::Net::AcceptCertificateHandler(true);

        Poco::Net::Context::VerificationMode verification_mode =
            Poco::Net::Context::VERIFY_RELAXED;
        if (IgnoreCert) {
            verification_mode = Poco::Net::Context::VERIFY_NONE;
        }
        Poco::Net::Context::Ptr context = new Poco::Net::Context(
            Poco::Net::Context::CLIENT_USE, "",
            verification_mode, 9, true, "ALL");

        Poco::Net::SSLManager::instance().initializeClient(
            0, acceptCertHandler, context);

        Poco::Net::HTTPSClientSession session(uri.getHost(), uri.getPort(),
                                              context);
        if (ProxySettings.IsConfigured()) {
            session.setProxy(ProxySettings.host, ProxySettings.port);
            if (ProxySettings.HasCredentials()) {
                session.setProxyCredentials(ProxySettings.username,
                                            ProxySettings.password);
            }
        }
        session.setKeepAlive(false);
        session.setTimeout(Poco::Timespan(10 * Poco::Timespan::SECONDS));

        Poco::Logger &logger = Poco::Logger::get("https_client");
        {
            std::stringstream ss;
            ss << "Sending request to " << relative_url << " ..";
            logger.debug(ss.str());
        }

        std::string encoded_url("");
        Poco::URI::encode(relative_url, "", encoded_url);
        Poco::Net::HTTPRequest req(method,
                                   encoded_url,
                                   Poco::Net::HTTPMessage::HTTP_1_1);
        req.setKeepAlive(false);
        req.setContentType("application/json");
        req.set("User-Agent", UserAgent());
        req.setChunkedTransferEncoding(true);

        Poco::Net::HTTPBasicCredentials cred(
            basic_auth_username, basic_auth_password);
        if (!basic_auth_username.empty() && !basic_auth_password.empty()) {
            cred.authenticate(req);
        }

        std::istringstream requestStream(payload);
        Poco::DeflatingInputStream gzipRequest(
            requestStream,
            Poco::DeflatingStreamBuf::STREAM_GZIP);
        Poco::DeflatingStreamBuf *pBuff = gzipRequest.rdbuf();

        Poco::Int64 size = pBuff->pubseekoff(0, std::ios::end, std::ios::in);
        pBuff->pubseekpos(0, std::ios::in);

        req.setContentLength(size);
        req.set("Content-Encoding", "gzip");
        req.set("Accept-Encoding", "gzip");

        session.sendRequest(req) << pBuff << std::flush;

        // Log out request contents
        std::stringstream request_string;
        req.write(request_string);
        logger.debug(request_string.str());

        logger.debug("Request sent. Receiving response..");

        // Receive response
        Poco::Net::HTTPResponse response;
        std::istream& is = session.receiveResponse(response);

        {
            std::stringstream ss;
            ss << "Response status code " << response.getStatus()
               << ", content length " << response.getContentLength()
               << ", content type " << response.getContentType();
            if (response.has("Content-Encoding")) {
                ss << ", content encoding " << response.get("Content-Encoding");
            } else {
                ss << ", unknown content encoding";
            }
            logger.debug(ss.str());
        }

        // Inflate, if gzip was sent
        if (response.has("Content-Encoding") &&
                "gzip" == response.get("Content-Encoding")) {
            Poco::InflatingInputStream inflater(
                is,
                Poco::InflatingStreamBuf::STREAM_GZIP);
            {
                std::stringstream ss;
                ss << inflater.rdbuf();
                *response_body = ss.str();
            }
        } else {
            std::istreambuf_iterator<char> eos;
            *response_body =
                std::string(std::istreambuf_iterator<char>(is), eos);
        }

        logger.trace(*response_body);

        if (response.getStatus() < 200 || response.getStatus() >= 300) {
            if (response_body->empty()) {
                std::stringstream description;
                description << "Request to server failed with status code: "
                            << response.getStatus();
                return description.str();
            }
            return "Request failed with error: " + *response_body;
        }

        // Debug encoding
        {
            std::stringstream ss;
            Poco::UTF8Encoding encoding;
            ss << "Response text encoding ASCII=" << encoding.isA("ASCII")
               << " Latin-1=" << encoding.isA("Latin-1")
               << " Latin-9=" << encoding.isA("Latin-9")
               << " Windows-1252=" << encoding.isA("Windows-1252")
               << " UTF-8=" << encoding.isA("UTF-8")
               << " UTF-16=" << encoding.isA("UTF-16");
            logger.debug(ss.str());
        }
    } catch(const Poco::Exception& exc) {
        return exc.displayText();
    } catch(const std::exception& ex) {
        return ex.what();
    } catch(const std::string& ex) {
        return ex;
    }
    return noError;
}

}   // namespace kopsik
<|endoftext|>


<commit_before>/*
 * PosixFileScanner.cpp
 *
 * Copyright (C) 2009-19 by RStudio, Inc.
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include <core/system/FileScanner.hpp>

#include <dirent.h>
#include <sys/stat.h>

#include <core/Error.hpp>
#include <core/Log.hpp>
#include <core/FilePath.hpp>
#include <core/BoostThread.hpp>

#include "config.h"

namespace rstudio {
namespace core {
namespace system {

namespace {

#if defined(__APPLE__) && !defined(HAVE_SCANDIR_POSIX)
int entryFilter(struct dirent *entry)
#else
int entryFilter(const struct dirent *entry)
#endif
{
   if (::strcmp(entry->d_name, ".") == 0 || ::strcmp(entry->d_name, "..") == 0)
      return 0;
   else
      return 1;
}

// note: because R may change LC_COLLATE, we cannot
// use strcoll (otherwise we run into race issues where
// the file monitor attempts to access LC_COLLATE just as
// R is replacing it). to avoid this, we use strcmp and
// don't sort according to locale.
#if !defined(HAVE_SCANDIR_POSIX)
int alphasort(const void* voidlhs, const void* voidrhs)
{
   const dirent** lhs = (const dirent**)voidlhs;
   const dirent** rhs = (const dirent**)voidrhs;
#else
int alphasort(const dirent** lhs, const dirent** rhs)
{
#endif
   return strcmp((*lhs)->d_name, (*rhs)->d_name);
}

// wrapper for scandir api
Error scanDir(const std::string& dirPath, std::vector<std::string>* pNames)
{
   // read directory contents into namelist
   struct dirent **namelist;
   int entries = ::scandir(dirPath.c_str(),
                           &namelist,
                           entryFilter,
                           alphasort);
   if (entries == -1)
   {
      Error error = systemError(errno, ERROR_LOCATION);
      error.addProperty("path", dirPath);
      return error;
   }

   // extract the namelist then free it
   for(int i=0; i<entries; i++)
   {
      // get the name (then free it)
      std::string name(namelist[i]->d_name,
#ifdef __APPLE__
                       namelist[i]->d_namlen);
#else
                       namelist[i]->d_reclen);
#endif
      ::free(namelist[i]);

      // add to the vector
      pNames->push_back(name);
   }
   ::free(namelist);

   return Success();
}

} // anonymous namespace

Error scanFiles(const tree<FileInfo>::iterator_base& fromNode,
                const FileScannerOptions& options,
                tree<FileInfo>* pTree)
{
   // clear all existing
   pTree->erase_children(fromNode);

   // create FilePath for root
   FilePath rootPath(fromNode->absolutePath());

   // yield if requested (only applies to recursive scans)
   if (options.recursive && options.yield)
      boost::this_thread::yield();

   // call onBeforeScanDir hook
   if (options.onBeforeScanDir)
   {
      Error error = options.onBeforeScanDir(*fromNode);
      if (error)
         return error;
   }

   // read directory contents
   std::vector<std::string> names;
   Error error = scanDir(fromNode->absolutePath(), &names);
   if (error)
      return error;

   // iterate over the names
   for (const std::string& name : names)
   {
      // compute the path
      std::string path = rootPath.childPath(name).absolutePath();

      // get the attributes
      struct stat st;
      int res = ::lstat(path.c_str(), &st);
      if (res == -1)
      {
         if (errno != ENOENT && errno != EACCES)
         {
            Error error = systemError(errno, ERROR_LOCATION);
            error.addProperty("path", path);
            LOG_ERROR(error);
         }
         continue;
      }

      // create the FileInfo
      FileInfo fileInfo;
      bool isSymlink = S_ISLNK(st.st_mode);
      if (S_ISDIR(st.st_mode))
      {
         fileInfo = FileInfo(path, true, isSymlink);
      }
      else
      {
         fileInfo = FileInfo(path,
                             false,
                             st.st_size,
#ifdef __APPLE__
                             st.st_mtimespec.tv_sec,
#else
                             st.st_mtime,
#endif
                             isSymlink);
      }

      // apply the filter (if any)
      if (!options.filter || options.filter(fileInfo))
      {
         // add the correct type of FileEntry
         if (fileInfo.isDirectory())
         {
            tree<FileInfo>::iterator_base child = pTree->append_child(fromNode,
                                                                      fileInfo);
            // recurse if requested and this isn't a link
            if (options.recursive && !fileInfo.isSymlink())
            {
               // try to scan the files in the subdirectory -- if we fail
               // we continue because we don't want one "bad" directory
               // to cause us to abort the entire scan. yes the tree
               // will be incomplete however it will be even more incompete
               // if we fail entirely
               Error error = scanFiles(child, options, pTree);
               if (error)
                  LOG_ERROR(error);
            }
         }
         else
         {
            pTree->append_child(fromNode, fileInfo);
         }
      }
   }

   // return success
   return Success();
}

} // namespace system
} // namespace core
} // namespace rstudio

<commit_msg>ported fix from pro back to open-source<commit_after>/*
 * PosixFileScanner.cpp
 *
 * Copyright (C) 2009-19 by RStudio, Inc.
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include <core/system/FileScanner.hpp>

#include <dirent.h>
#include <sys/stat.h>

#include <core/Error.hpp>
#include <core/Log.hpp>
#include <core/FilePath.hpp>
#include <core/BoostThread.hpp>

#include "config.h"

namespace rstudio {
namespace core {
namespace system {

namespace {

#if defined(__APPLE__) && !defined(HAVE_SCANDIR_POSIX)
int entryFilter(struct dirent *entry)
#else
int entryFilter(const struct dirent *entry)
#endif
{
   if (::strcmp(entry->d_name, ".") == 0 || ::strcmp(entry->d_name, "..") == 0)
      return 0;
   else
      return 1;
}

// note: because R may change LC_COLLATE, we cannot
// use strcoll (otherwise we run into race issues where
// the file monitor attempts to access LC_COLLATE just as
// R is replacing it). to avoid this, we use strcmp and
// don't sort according to locale.
#if !defined(HAVE_SCANDIR_POSIX)
int alphasort(const void* voidlhs, const void* voidrhs)
{
   const dirent** lhs = (const dirent**)voidlhs;
   const dirent** rhs = (const dirent**)voidrhs;
#else
int alphasort(const dirent** lhs, const dirent** rhs)
{
#endif
   return strcmp((*lhs)->d_name, (*rhs)->d_name);
}

// wrapper for scandir api
Error scanDir(const std::string& dirPath, std::vector<std::string>* pNames)
{
   // read directory contents into namelist
   struct dirent **namelist;
   int entries = ::scandir(dirPath.c_str(),
                           &namelist,
                           entryFilter,
                           alphasort);
   if (entries == -1)
   {
      Error error = systemError(errno, ERROR_LOCATION);
      error.addProperty("path", dirPath);
      return error;
   }

   // extract the namelist then free it
   for(int i=0; i<entries; i++)
   {
      // get the name (then free it)
      std::string name(namelist[i]->d_name);
      ::free(namelist[i]);

      // add to the vector
      pNames->push_back(name);
   }
   ::free(namelist);

   return Success();
}

} // anonymous namespace

Error scanFiles(const tree<FileInfo>::iterator_base& fromNode,
                const FileScannerOptions& options,
                tree<FileInfo>* pTree)
{
   // clear all existing
   pTree->erase_children(fromNode);

   // create FilePath for root
   FilePath rootPath(fromNode->absolutePath());

   // yield if requested (only applies to recursive scans)
   if (options.recursive && options.yield)
      boost::this_thread::yield();

   // call onBeforeScanDir hook
   if (options.onBeforeScanDir)
   {
      Error error = options.onBeforeScanDir(*fromNode);
      if (error)
         return error;
   }

   // read directory contents
   std::vector<std::string> names;
   Error error = scanDir(fromNode->absolutePath(), &names);
   if (error)
      return error;

   // iterate over the names
   for (const std::string& name : names)
   {
      // compute the path
      std::string path = rootPath.childPath(name).absolutePath();

      // get the attributes
      struct stat st;
      int res = ::lstat(path.c_str(), &st);
      if (res == -1)
      {
         if (errno != ENOENT && errno != EACCES)
         {
            Error error = systemError(errno, ERROR_LOCATION);
            error.addProperty("path", path);
            LOG_ERROR(error);
         }
         continue;
      }

      // create the FileInfo
      FileInfo fileInfo;
      bool isSymlink = S_ISLNK(st.st_mode);
      if (S_ISDIR(st.st_mode))
      {
         fileInfo = FileInfo(path, true, isSymlink);
      }
      else
      {
         fileInfo = FileInfo(path,
                             false,
                             st.st_size,
#ifdef __APPLE__
                             st.st_mtimespec.tv_sec,
#else
                             st.st_mtime,
#endif
                             isSymlink);
      }

      // apply the filter (if any)
      if (!options.filter || options.filter(fileInfo))
      {
         // add the correct type of FileEntry
         if (fileInfo.isDirectory())
         {
            tree<FileInfo>::iterator_base child = pTree->append_child(fromNode,
                                                                      fileInfo);
            // recurse if requested and this isn't a link
            if (options.recursive && !fileInfo.isSymlink())
            {
               // try to scan the files in the subdirectory -- if we fail
               // we continue because we don't want one "bad" directory
               // to cause us to abort the entire scan. yes the tree
               // will be incomplete however it will be even more incompete
               // if we fail entirely
               Error error = scanFiles(child, options, pTree);
               if (error)
                  LOG_ERROR(error);
            }
         }
         else
         {
            pTree->append_child(fromNode, fileInfo);
         }
      }
   }

   // return success
   return Success();
}

} // namespace system
} // namespace core
} // namespace rstudio

<|endoftext|>


<commit_before>#pragma once
#include <cassert>
#include "gl_1_5.h"

#define YKS_CHECK_GL assert(glGetError() == GL_NO_ERROR)
#ifdef _DEBUG
#define YKS_CHECK_GL_PARANOID assert(glGetError() == GL_NO_ERROR)
#else
#define YKS_CHECK_GL_PARANOID
#endif
<commit_msg>Make GL assert more debugger friendly<commit_after>#pragma once
#include <cassert>
#include "gl_1_5.h"

inline void check_gl_error() {
	GLenum error = glGetError();
	assert(error == GL_NO_ERROR);
}

#define YKS_CHECK_GL check_gl_error()
#ifdef _DEBUG
#define YKS_CHECK_GL_PARANOID check_gl_error()
#else
#define YKS_CHECK_GL_PARANOID
#endif
<|endoftext|>


<commit_before>#include <algorithm>
#include <map>
#include <string>
#include <limits>

#include "Prefetch.h"
#include "CodeGen_Internal.h"
#include "IRMutator.h"
#include "IROperator.h"
#include "Bounds.h"
#include "Scope.h"
#include "Simplify.h"
#include "Substitute.h"
#include "Util.h"

namespace Halide {
namespace Internal {

using std::map;
using std::string;
using std::vector;
using std::stack;

class InjectPrefetch : public IRMutator {
public:
    InjectPrefetch(const map<string, Function> &e)
        : env(e) { }
private:
    const map<string, Function> &env;
    Scope<Interval> scope;

private:
    using IRMutator::visit;

    // Strip down the tuple name, e.g. f.*.var into f
    string tuple_func(const string &name) {
        vector<string> v = split_string(name, ".");
        internal_assert(v.size() > 0);
        return v[0];
    }

    // Strip down the tuple name, e.g. f.*.var into var
    string tuple_var(const string &name) {
        vector<string> v = split_string(name, ".");
        internal_assert(v.size() > 0);
        return v[v.size()-1];
    }

    Function get_func(const string &name) {
        map<string, Function>::const_iterator iter = env.find(name);
        internal_assert(iter != env.end()) << "Realize node refers to function not in environment.\n";
        return iter->second;
    }

    void visit(const LetStmt *op) {
        Interval in = bounds_of_expr_in_scope(op->value, scope);
        scope.push(op->name, in);
        op->body.accept(this);
        scope.pop(op->name);
    }

    void visit(const For *op) {
        // At this stage of lowering, loop_min and loop_max
        // conveniently exist in scope.
        Interval in(Variable::make(Int(32), op->name + ".loop_min"),
                    Variable::make(Int(32), op->name + ".loop_max"));

        scope.push(op->name, in);

        Stmt body = op->body;

        string func_name = tuple_func(op->name);
        string var_name  = tuple_var(op->name);
        vector<Prefetch> &prefetches = get_func(func_name).schedule().prefetches();

        std::cerr << "Prefetch: " << op->name << " " << func_name << " " << var_name;
        if (prefetches.empty()) {
            std::cerr << " No prefetches in schedule\n";
        } else {
            std::cerr << " Checking prefetches\n";
        }

        // Todo: Check to see if op->name is in prefetches
        for (const Prefetch &p : prefetches) {
            std::cerr << "Prefetch: " << p.var
                               << " " << p.offset << "\n";
            if (p.var == var_name) {
                std::cerr << " matched on " << var_name << "\n";
                string fetch_func = "halide.hexagon.l2fetch.Rtt";

                Interval prein(in.min + p.offset, in.max + p.offset);
                scope.push(op->name, prein);

                map<string, Box> r;
                r = boxes_required(op, scope);

                // Add prefetch to body on inputs
                // Todo: For each input...
                Expr tmp = Expr(0);
                Stmt prefetch =
                    Evaluate::make(Call::make(Int(32), fetch_func,
                                      {tmp, p.offset}, Call::Extern));
                body = Block::make({prefetch, body});
            }
        }

        body = mutate(body);
        stmt = For::make(op->name, op->min, op->extent, op->for_type, op->device_api, body);

        scope.pop(op->name);
    }

};

Stmt inject_prefetch(Stmt s, const std::map<std::string, Function> &env)
{
    return InjectPrefetch(env).mutate(s);
}

}
}
<commit_msg>Add back missing scope pop<commit_after>#include <algorithm>
#include <map>
#include <string>
#include <limits>

#include "Prefetch.h"
#include "CodeGen_Internal.h"
#include "IRMutator.h"
#include "IROperator.h"
#include "Bounds.h"
#include "Scope.h"
#include "Simplify.h"
#include "Substitute.h"
#include "Util.h"

namespace Halide {
namespace Internal {

using std::map;
using std::string;
using std::vector;
using std::stack;

class InjectPrefetch : public IRMutator {
public:
    InjectPrefetch(const map<string, Function> &e)
        : env(e) { }
private:
    const map<string, Function> &env;
    Scope<Interval> scope;

private:
    using IRMutator::visit;

    // Strip down the tuple name, e.g. f.*.var into f
    string tuple_func(const string &name) {
        vector<string> v = split_string(name, ".");
        internal_assert(v.size() > 0);
        return v[0];
    }

    // Strip down the tuple name, e.g. f.*.var into var
    string tuple_var(const string &name) {
        vector<string> v = split_string(name, ".");
        internal_assert(v.size() > 0);
        return v[v.size()-1];
    }

    Function get_func(const string &name) {
        map<string, Function>::const_iterator iter = env.find(name);
        internal_assert(iter != env.end()) << "Realize node refers to function not in environment.\n";
        return iter->second;
    }

    void visit(const LetStmt *op) {
        Interval in = bounds_of_expr_in_scope(op->value, scope);
        scope.push(op->name, in);
        op->body.accept(this);
        scope.pop(op->name);
    }

    void visit(const For *op) {
        // At this stage of lowering, loop_min and loop_max
        // conveniently exist in scope.
        Interval in(Variable::make(Int(32), op->name + ".loop_min"),
                    Variable::make(Int(32), op->name + ".loop_max"));

        scope.push(op->name, in);

        Stmt body = op->body;

        string func_name = tuple_func(op->name);
        string var_name  = tuple_var(op->name);
        vector<Prefetch> &prefetches = get_func(func_name).schedule().prefetches();

        std::cerr << "Prefetch: " << op->name << " " << func_name << " " << var_name;
        if (prefetches.empty()) {
            std::cerr << " No prefetches in schedule\n";
        } else {
            std::cerr << " Checking prefetches\n";
        }

        // Todo: Check to see if op->name is in prefetches
        for (const Prefetch &p : prefetches) {
            std::cerr << "Prefetch: " << p.var
                               << " " << p.offset << "\n";
            if (p.var == var_name) {
                std::cerr << " matched on " << var_name << "\n";
                string fetch_func = "halide.hexagon.l2fetch.Rtt";

                Interval prein(in.min + p.offset, in.max + p.offset);
                scope.push(op->name, prein);

                map<string, Box> r;
                r = boxes_required(op, scope);

                scope.pop(op->name);

                // Add prefetch to body on inputs
                // Todo: For each input...
                Expr tmp = Expr(0);
                Stmt prefetch =
                    Evaluate::make(Call::make(Int(32), fetch_func,
                                      {tmp, p.offset}, Call::Extern));
                body = Block::make({prefetch, body});
            }
        }

        body = mutate(body);
        stmt = For::make(op->name, op->min, op->extent, op->for_type, op->device_api, body);

        scope.pop(op->name);
    }

};

Stmt inject_prefetch(Stmt s, const std::map<std::string, Function> &env)
{
    return InjectPrefetch(env).mutate(s);
}

}
}
<|endoftext|>


<commit_before>/*
Copyright (c) 2016, oasi-adamay
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

* Neither the name of glsCV nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "stdafx.h"

/*-----------------------------------------------------------------------------
include
*/
#include "glsMacro.h"
#include "GlsMat.h"
#include "glsShader.h"

#include "glsFft.h"
#include "glsCopy.h"	//tiled / untiled

#define _USE_MATH_DEFINES
#include <math.h>

#ifdef _DEBUG
//#if 1
#include "Timer.h"
#define _TMR_(...)  Timer tmr(__VA_ARGS__)
#else
#define _TMR_(...)
#endif

namespace gls
{

// glsFft shader
class glsShaderFft : public glsShaderBase
{
protected:
	string FragmentShaderCode(void);
	list<string> UniformNameList(void);

public:
	glsShaderFft(void) :glsShaderBase(__FUNCTION__){}

};

//-----------------------------------------------------------------------------
//global
glsShaderFft ShaderFft;

//-----------------------------------------------------------------------------
//glsShaderFft
string glsShaderFft::FragmentShaderCode(void){
	const char fragmentShaderCode[] = TO_STR(
#version 330 core\n
precision highp float;\n
uniform sampler2D	texSrc0;\n
uniform sampler2D	texSrc1;\n
uniform sampler2D	texW;\n
uniform  int i_flag;	//bit0:(0:holizontal 1:vertical)\n
uniform  int i_N;\n
uniform  int i_p;\n
uniform  int i_q;\n
uniform  float f_xscl;\n
uniform  float f_yscl;\n
uniform  float f_xconj;\n
uniform  float f_yconj;\n
\n
layout (location = 0) out vec2 dst0;\n
layout (location = 1) out vec2 dst1;\n
\n
#define FLAG_DIR	 (1<<0)\n
\n
\n
int insertZeroBits(\n
	const int src,\n
	const int idx,\n
	const int num\n
	)\n
{\n
	int ret = src << num;\n
	ret &= ~((1 << (idx + num)) - 1);\n
	ret |= src & ((1 << idx) - 1);\n
	return ret;\n
}\n
\n
void main(void)\n
{\n
	int p = i_p;\n
	int q = i_q;\n
	int N = i_N;\n
	int dir = ((i_flag & FLAG_DIR)==0) ?0:1;\n
	float xscl = f_xscl;\n
	float yscl = f_yscl;\n
	float xconj = f_xconj;\n
	float yconj = f_yconj;\n
\n
	int n;\n
	vec2 x0;\n
	vec2 x1;\n
	vec2 w;\n
\n
	n= int(gl_FragCoord[dir]);\n
	int iw = (n >> q) << q;\n
	int ix0 = insertZeroBits(n, q, 1);\n
	int ix1 = ix0 + (1 << q);\n
	w = texelFetch(texW,ivec2(iw,0),0).rg;\n
\n
\n
	if(dir ==0){\n
		if(ix0 < N/2) x0 = texelFetch(texSrc0,ivec2(ix0,gl_FragCoord.y),0).rg;\n
		else x0 = texelFetch(texSrc1,ivec2(ix0-N/2,gl_FragCoord.y),0).rg;\n
\n
		if(ix1 < N/2) x1 = texelFetch(texSrc0,ivec2(ix1,gl_FragCoord.y),0).rg;\n
		else x1 = texelFetch(texSrc1,ivec2(ix1-N/2,gl_FragCoord.y),0).rg;\n
	}\n
	else{\n
		if(ix0 < N/2) x0 = texelFetch(texSrc0,ivec2(gl_FragCoord.x,ix0),0).rg;\n
		else x0 = texelFetch(texSrc1,ivec2(gl_FragCoord.x,ix0-N/2),0).rg;\n
\n
		if(ix1 < N/2) x1 = texelFetch(texSrc0,ivec2(gl_FragCoord.x,ix1),0).rg;\n
		else x1 = texelFetch(texSrc1,ivec2(gl_FragCoord.x,ix1-N/2),0).rg;\n
	}\n
\n
//	x0 = x0*xscl;\n
//	x1 = x1*xscl;\n
	x0.g = x0.g*xconj;\n
	x1.g = x1.g*xconj;\n
\n
	vec2 tmp;\n
	tmp.r = x1.r * w.r - x1.g * w.g;\n
	tmp.g = x1.r * w.g + x1.g * w.r;\n
\n
	vec2 y0;\n
	vec2 y1;\n
\n
	y0 = x0 + tmp;\n
	y1 = x0 - tmp;\n
\n
	y0 = y0*yscl;\n
	y1 = y1*yscl;\n
	y0.g = y0.g*yconj;\n
	y1.g = y1.g*yconj;\n
\n
	dst0 = y0;\n
	dst1 = y1;\n
\n
}\n
);
	return fragmentShaderCode;
}

list<string> glsShaderFft::UniformNameList(void){
	list<string> lst;
	lst.push_back("texSrc0");
	lst.push_back("texSrc1");
	lst.push_back("texW");
	lst.push_back("i_flag");
	lst.push_back("i_N");
	lst.push_back("i_p");
	lst.push_back("i_q");
	lst.push_back("f_xscl");
	lst.push_back("f_yscl");
	lst.push_back("f_xconj");
	lst.push_back("f_yconj");
	return lst;
}

//---------------------------------------------------------------------------
//value is power of 2
static bool IsPow2(unsigned int x){
	return (((x)&(x - 1)) == 0);
}

//-----------------------------------------------------------------------------
void fft(const GlsMat& src, GlsMat& dst, int flag){
	GLS_Assert(src.channels() == 2);
	GLS_Assert(src.depth() == CV_32F);

	int N = src.cols;
	GLS_Assert(IsPow2(N));

	Size blkNum(2,2);
	vector<vector<GlsMat>> _dst0 = vector<vector<GlsMat>>(blkNum.height, vector<GlsMat>(blkNum.width));
	vector<vector<GlsMat>> _dst1 = vector<vector<GlsMat>>(blkNum.height, vector<GlsMat>(blkNum.width));

	gls::tiled(src, _dst0, blkNum);
	for (int by = 0; by < blkNum.height; by++){
		for (int bx = 0; bx < blkNum.width; bx++){
			_dst1[by][bx] = GlsMat(Size(src.cols / blkNum.width, src.rows / blkNum.height), src.type());
		}
	}

	GlsMat texW(Size(N / 2, 1), src.type());

	//---------------------------------
	// upload twidle texture
	{
		_TMR_("-twidle:  \t");

		Mat w(Size(N / 2, 1), CV_32FC2);
#ifdef _OPENMP
#pragma omp parallel for
#endif
		for (int n = 0; n < N / 2; n++){
			float jw = (float)(-2 * M_PI * n / N);
			Vec2f val(cos(jw), sin(jw));
			w.at<Vec2f>(0, n) = val;
		}
		texW.upload(w);

		//vector<vec2> w(N / 2);
		// --- twidle ----
		//#ifdef _OPENMP
		//#pragma omp parallel for
		//#endif
		//for (int n = 0; n < N / 2; n++){
		//	float jw = (float)(-2 * M_PI * n / N);
		//	w[n][0] = cos(jw);
		//	w[n][1] = sin(jw);
		//}
		//void* data = &w[0];

		//glBindTexture(GL_TEXTURE_2D, texW);
		//glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, (GLsizei)w.size(), 1, texture.glFormat(), texture.glType(), data);
		//glBindTexture(GL_TEXTURE_2D, 0);
	}

	vector<vector<GlsMat>>* texbuf[2] = { &_dst0, &_dst1 };

	//Execute
	int bank = 0;

	{
		_TMR_("-execute:\t");

		int Q = 0;
		while ((1 << Q) < N){ Q++; }

		vector<GlsMat> texSrc(2);
		vector<GlsMat> texDst(2);

		// --- FFT rows ----
		for (int p = 0, q = Q - 1; q >= 0; p++, q--, bank = bank ^ 1) {
			for (int i = 0; i < 2; i++){
				for (int j = 0; j < 2; j++){
					texSrc[j] = (*texbuf[bank])[i][j];
					texDst[j] = (*texbuf[bank ^ 1])[i][j];
				}
				float yscl = ((flag & GLS_FFT_SCALE) && (q == 0)) ? 1.0f / (float)N : 1.0f;
				float xscl = 1.0f;
				float xconj = ((flag & GLS_FFT_INVERSE) && (p == 0)) ? -1.0f : 1.0f;
				float yconj = 1.0f;
				ShaderFft.Execute(texSrc[0], texSrc[1], texW, 0, N, p, q, xscl, yscl, xconj, yconj, texDst[0], texDst[1]);

			}
		}
		// --- FFT cols ----
		for (int p = 0, q = Q - 1; q >= 0; p++, q--, bank = bank ^ 1) {
			for (int j = 0; j < 2; j++){
				for (int i = 0; i < 2; i++){
					texSrc[i] = (*texbuf[bank])[i][j];
					texDst[i] = (*texbuf[bank ^ 1])[i][j];
				}
				float yscl = ((flag & GLS_FFT_SCALE) && (q == 0)) ? 1.0f / (float)N : 1.0f;
				float xscl = 1.0f;
				float xconj = 1.0f;
				float yconj = ((flag & GLS_FFT_INVERSE) && (q == 0)) ? -1.0f : 1.0f;
				ShaderFft.Execute(texSrc[0], texSrc[1], texW, 1, N, p, q, xscl, yscl, xconj, yconj, texDst[0], texDst[1]);
			}
		}
	}

	if (flag & GLS_FFT_SHIFT){
		(*texbuf[bank ^ 1])[0][0] = (*texbuf[bank])[1][1];
		(*texbuf[bank ^ 1])[0][1] = (*texbuf[bank])[1][0];
		(*texbuf[bank ^ 1])[1][0] = (*texbuf[bank])[0][1];
		(*texbuf[bank ^ 1])[1][1] = (*texbuf[bank])[0][0];
		bank = bank ^ 1;
	}

	gls::untiled(*texbuf[bank], dst);
}

void fft(const Mat& src, Mat& dst, int flag){
	CV_Assert(src.type() == CV_32FC2);
	CV_Assert(src.cols == src.rows);

	int N = src.cols;
	CV_Assert(IsPow2(N));

	GlsMat _src(src.size(), src.type());
	GlsMat _dst;

	//---------------------------------
	//upload
	_src.upload(src);

	//---------------------------------
	//fft
	gls::fft(_src, _dst,flag);

	//---------------------------------
	//download
	_dst.download(dst);

}

}//namespace gls

<commit_msg>glsFFT 入力が実数配列の時は、内部で複素配列に変換<commit_after>/*
Copyright (c) 2016, oasi-adamay
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

* Neither the name of glsCV nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "stdafx.h"

/*-----------------------------------------------------------------------------
include
*/
#include "glsMacro.h"
#include "GlsMat.h"
#include "glsShader.h"

#include "glsFft.h"
#include "glsCopy.h"	//tiled / untiled
#include "glsMerge.h"

#define _USE_MATH_DEFINES
#include <math.h>

#ifdef _DEBUG
//#if 1
#include "Timer.h"
#define _TMR_(...)  Timer tmr(__VA_ARGS__)
#else
#define _TMR_(...)
#endif

namespace gls
{

// glsFft shader
class glsShaderFft : public glsShaderBase
{
protected:
	string FragmentShaderCode(void);
	list<string> UniformNameList(void);

public:
	glsShaderFft(void) :glsShaderBase(__FUNCTION__){}

};

//-----------------------------------------------------------------------------
//global
glsShaderFft ShaderFft;

//-----------------------------------------------------------------------------
//glsShaderFft
string glsShaderFft::FragmentShaderCode(void){
	const char fragmentShaderCode[] = TO_STR(
#version 330 core\n
precision highp float;\n
uniform sampler2D	texSrc0;\n
uniform sampler2D	texSrc1;\n
uniform sampler2D	texW;\n
uniform  int i_flag;	//bit0:(0:holizontal 1:vertical)\n
uniform  int i_N;\n
uniform  int i_p;\n
uniform  int i_q;\n
uniform  float f_xscl;\n
uniform  float f_yscl;\n
uniform  float f_xconj;\n
uniform  float f_yconj;\n
\n
layout (location = 0) out vec2 dst0;\n
layout (location = 1) out vec2 dst1;\n
\n
#define FLAG_DIR	 (1<<0)\n
\n
\n
int insertZeroBits(\n
	const int src,\n
	const int idx,\n
	const int num\n
	)\n
{\n
	int ret = src << num;\n
	ret &= ~((1 << (idx + num)) - 1);\n
	ret |= src & ((1 << idx) - 1);\n
	return ret;\n
}\n
\n
void main(void)\n
{\n
	int p = i_p;\n
	int q = i_q;\n
	int N = i_N;\n
	int dir = ((i_flag & FLAG_DIR)==0) ?0:1;\n
	float xscl = f_xscl;\n
	float yscl = f_yscl;\n
	float xconj = f_xconj;\n
	float yconj = f_yconj;\n
\n
	int n;\n
	vec2 x0;\n
	vec2 x1;\n
	vec2 w;\n
\n
	n= int(gl_FragCoord[dir]);\n
	int iw = (n >> q) << q;\n
	int ix0 = insertZeroBits(n, q, 1);\n
	int ix1 = ix0 + (1 << q);\n
	w = texelFetch(texW,ivec2(iw,0),0).rg;\n
\n
\n
	if(dir ==0){\n
		if(ix0 < N/2) x0 = texelFetch(texSrc0,ivec2(ix0,gl_FragCoord.y),0).rg;\n
		else x0 = texelFetch(texSrc1,ivec2(ix0-N/2,gl_FragCoord.y),0).rg;\n
\n
		if(ix1 < N/2) x1 = texelFetch(texSrc0,ivec2(ix1,gl_FragCoord.y),0).rg;\n
		else x1 = texelFetch(texSrc1,ivec2(ix1-N/2,gl_FragCoord.y),0).rg;\n
	}\n
	else{\n
		if(ix0 < N/2) x0 = texelFetch(texSrc0,ivec2(gl_FragCoord.x,ix0),0).rg;\n
		else x0 = texelFetch(texSrc1,ivec2(gl_FragCoord.x,ix0-N/2),0).rg;\n
\n
		if(ix1 < N/2) x1 = texelFetch(texSrc0,ivec2(gl_FragCoord.x,ix1),0).rg;\n
		else x1 = texelFetch(texSrc1,ivec2(gl_FragCoord.x,ix1-N/2),0).rg;\n
	}\n
\n
//	x0 = x0*xscl;\n
//	x1 = x1*xscl;\n
	x0.g = x0.g*xconj;\n
	x1.g = x1.g*xconj;\n
\n
	vec2 tmp;\n
	tmp.r = x1.r * w.r - x1.g * w.g;\n
	tmp.g = x1.r * w.g + x1.g * w.r;\n
\n
	vec2 y0;\n
	vec2 y1;\n
\n
	y0 = x0 + tmp;\n
	y1 = x0 - tmp;\n
\n
	y0 = y0*yscl;\n
	y1 = y1*yscl;\n
	y0.g = y0.g*yconj;\n
	y1.g = y1.g*yconj;\n
\n
	dst0 = y0;\n
	dst1 = y1;\n
\n
}\n
);
	return fragmentShaderCode;
}

list<string> glsShaderFft::UniformNameList(void){
	list<string> lst;
	lst.push_back("texSrc0");
	lst.push_back("texSrc1");
	lst.push_back("texW");
	lst.push_back("i_flag");
	lst.push_back("i_N");
	lst.push_back("i_p");
	lst.push_back("i_q");
	lst.push_back("f_xscl");
	lst.push_back("f_yscl");
	lst.push_back("f_xconj");
	lst.push_back("f_yconj");
	return lst;
}

//---------------------------------------------------------------------------
//value is power of 2
static bool IsPow2(unsigned int x){
	return (((x)&(x - 1)) == 0);
}

//-----------------------------------------------------------------------------
void fft(const GlsMat& _src, GlsMat& dst, int flag){
	GLS_Assert(_src.channels() == 2 || _src.channels() == 1);
	GLS_Assert(_src.depth() == CV_32F);

	int N = _src.cols;
	GLS_Assert(IsPow2(N));

	Size blkNum(2,2);
	vector<vector<GlsMat>> _dst0 = vector<vector<GlsMat>>(blkNum.height, vector<GlsMat>(blkNum.width));
	vector<vector<GlsMat>> _dst1 = vector<vector<GlsMat>>(blkNum.height, vector<GlsMat>(blkNum.width));

	GlsMat src;
	if (_src.channels() == 1){
		// to complex mat
		vector<GlsMat> tmp(2);
		tmp[0] = _src;
		gls::merge(tmp, src);
	}
	else{
		src = _src;
	}

	gls::tiled(src, _dst0, blkNum);
	for (int by = 0; by < blkNum.height; by++){
		for (int bx = 0; bx < blkNum.width; bx++){
			_dst1[by][bx] = GlsMat(Size(src.cols / blkNum.width, src.rows / blkNum.height), src.type());
		}
	}

	GlsMat texW(Size(N / 2, 1), src.type());

	//---------------------------------
	// upload twidle texture
	{
		_TMR_("-twidle:  \t");

		Mat w(Size(N / 2, 1), CV_32FC2);
#ifdef _OPENMP
#pragma omp parallel for
#endif
		for (int n = 0; n < N / 2; n++){
			float jw = (float)(-2 * M_PI * n / N);
			Vec2f val(cos(jw), sin(jw));
			w.at<Vec2f>(0, n) = val;
		}
		texW.upload(w);

		//vector<vec2> w(N / 2);
		// --- twidle ----
		//#ifdef _OPENMP
		//#pragma omp parallel for
		//#endif
		//for (int n = 0; n < N / 2; n++){
		//	float jw = (float)(-2 * M_PI * n / N);
		//	w[n][0] = cos(jw);
		//	w[n][1] = sin(jw);
		//}
		//void* data = &w[0];

		//glBindTexture(GL_TEXTURE_2D, texW);
		//glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, (GLsizei)w.size(), 1, texture.glFormat(), texture.glType(), data);
		//glBindTexture(GL_TEXTURE_2D, 0);
	}

	vector<vector<GlsMat>>* texbuf[2] = { &_dst0, &_dst1 };

	//Execute
	int bank = 0;

	{
		_TMR_("-execute:\t");

		int Q = 0;
		while ((1 << Q) < N){ Q++; }

		vector<GlsMat> texSrc(2);
		vector<GlsMat> texDst(2);

		// --- FFT rows ----
		for (int p = 0, q = Q - 1; q >= 0; p++, q--, bank = bank ^ 1) {
			for (int i = 0; i < 2; i++){
				for (int j = 0; j < 2; j++){
					texSrc[j] = (*texbuf[bank])[i][j];
					texDst[j] = (*texbuf[bank ^ 1])[i][j];
				}
				float yscl = ((flag & GLS_FFT_SCALE) && (q == 0)) ? 1.0f / (float)N : 1.0f;
				float xscl = 1.0f;
				float xconj = ((flag & GLS_FFT_INVERSE) && (p == 0)) ? -1.0f : 1.0f;
				float yconj = 1.0f;
				ShaderFft.Execute(texSrc[0], texSrc[1], texW, 0, N, p, q, xscl, yscl, xconj, yconj, texDst[0], texDst[1]);

			}
		}
		// --- FFT cols ----
		for (int p = 0, q = Q - 1; q >= 0; p++, q--, bank = bank ^ 1) {
			for (int j = 0; j < 2; j++){
				for (int i = 0; i < 2; i++){
					texSrc[i] = (*texbuf[bank])[i][j];
					texDst[i] = (*texbuf[bank ^ 1])[i][j];
				}
				float yscl = ((flag & GLS_FFT_SCALE) && (q == 0)) ? 1.0f / (float)N : 1.0f;
				float xscl = 1.0f;
				float xconj = 1.0f;
				float yconj = ((flag & GLS_FFT_INVERSE) && (q == 0)) ? -1.0f : 1.0f;
				ShaderFft.Execute(texSrc[0], texSrc[1], texW, 1, N, p, q, xscl, yscl, xconj, yconj, texDst[0], texDst[1]);
			}
		}
	}

	if (flag & GLS_FFT_SHIFT){
		(*texbuf[bank ^ 1])[0][0] = (*texbuf[bank])[1][1];
		(*texbuf[bank ^ 1])[0][1] = (*texbuf[bank])[1][0];
		(*texbuf[bank ^ 1])[1][0] = (*texbuf[bank])[0][1];
		(*texbuf[bank ^ 1])[1][1] = (*texbuf[bank])[0][0];
		bank = bank ^ 1;
	}

	gls::untiled(*texbuf[bank], dst);
}

void fft(const Mat& src, Mat& dst, int flag){
	CV_Assert(src.type() == CV_32FC2);
	CV_Assert(src.cols == src.rows);

	int N = src.cols;
	CV_Assert(IsPow2(N));

	GlsMat _src(src.size(), src.type());
	GlsMat _dst;

	//---------------------------------
	//upload
	_src.upload(src);

	//---------------------------------
	//fft
	gls::fft(_src, _dst,flag);

	//---------------------------------
	//download
	_dst.download(dst);

}

}//namespace gls

<|endoftext|>


<commit_before>
/*
 * Copyright 2011 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */
#include "gm.h"
#include "SkGradientShader.h"

namespace skiagm {

struct GradData {
    int             fCount;
    const SkColor*  fColors;
    const SkScalar* fPos;
};

static const SkColor gColors[] = {
    SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE, SK_ColorBLACK
};
static const SkScalar gPos0[] = { 0, SK_Scalar1 };
static const SkScalar gPos1[] = { SK_Scalar1/4, SK_Scalar1*3/4 };
static const SkScalar gPos2[] = {
    0, SK_Scalar1/8, SK_Scalar1/2, SK_Scalar1*7/8, SK_Scalar1
};

static const GradData gGradData[] = {
    { 2, gColors, NULL },
    { 2, gColors, gPos0 },
    { 2, gColors, gPos1 },
    { 5, gColors, NULL },
    { 5, gColors, gPos2 }
};

static SkShader* MakeLinear(const SkPoint pts[2], const GradData& data,
                            SkShader::TileMode tm, SkUnitMapper* mapper) {
    return SkGradientShader::CreateLinear(pts, data.fColors, data.fPos,
                                          data.fCount, tm, mapper);
}

static SkShader* MakeRadial(const SkPoint pts[2], const GradData& data,
                            SkShader::TileMode tm, SkUnitMapper* mapper) {
    SkPoint center;
    center.set(SkScalarAve(pts[0].fX, pts[1].fX),
               SkScalarAve(pts[0].fY, pts[1].fY));
    return SkGradientShader::CreateRadial(center, center.fX, data.fColors,
                                          data.fPos, data.fCount, tm, mapper);
}

static SkShader* MakeSweep(const SkPoint pts[2], const GradData& data,
                           SkShader::TileMode tm, SkUnitMapper* mapper) {
    SkPoint center;
    center.set(SkScalarAve(pts[0].fX, pts[1].fX),
               SkScalarAve(pts[0].fY, pts[1].fY));
    return SkGradientShader::CreateSweep(center.fX, center.fY, data.fColors,
                                         data.fPos, data.fCount, mapper);
}

static SkShader* Make2Radial(const SkPoint pts[2], const GradData& data,
                             SkShader::TileMode tm, SkUnitMapper* mapper) {
    SkPoint center0, center1;
    center0.set(SkScalarAve(pts[0].fX, pts[1].fX),
                SkScalarAve(pts[0].fY, pts[1].fY));
    center1.set(SkScalarInterp(pts[0].fX, pts[1].fX, SkIntToScalar(3)/5),
                SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4));
    return SkGradientShader::CreateTwoPointRadial(
                                                  center1, (pts[1].fX - pts[0].fX) / 7,
                                                  center0, (pts[1].fX - pts[0].fX) / 2,
                                                  data.fColors, data.fPos, data.fCount, tm, mapper);
}

typedef SkShader* (*GradMaker)(const SkPoint pts[2], const GradData& data,
                               SkShader::TileMode tm, SkUnitMapper* mapper);
static const GradMaker gGradMakers[] = {
    MakeLinear, MakeRadial, MakeSweep, Make2Radial
};

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

class GradientsGM : public GM {
public:
	GradientsGM() {}

protected:
    SkString onShortName() {
        return SkString("gradients");
    }

    virtual SkISize onISize() { return make_isize(640, 510); }

    void drawBG(SkCanvas* canvas) {
        canvas->drawColor(0xFFDDDDDD);
    }

    virtual void onDraw(SkCanvas* canvas) {
        this->drawBG(canvas);

        SkPoint pts[2] = {
            { 0, 0 },
            { SkIntToScalar(100), SkIntToScalar(100) }
        };
        SkShader::TileMode tm = SkShader::kClamp_TileMode;
        SkRect r = { 0, 0, SkIntToScalar(100), SkIntToScalar(100) };
        SkPaint paint;
        paint.setAntiAlias(true);

        canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
        for (size_t i = 0; i < SK_ARRAY_COUNT(gGradData); i++) {
            canvas->save();
            for (size_t j = 0; j < SK_ARRAY_COUNT(gGradMakers); j++) {
                SkShader* shader = gGradMakers[j](pts, gGradData[i], tm, NULL);
                paint.setShader(shader);
                canvas->drawRect(r, paint);
                shader->unref();
                canvas->translate(0, SkIntToScalar(120));
            }
            canvas->restore();
            canvas->translate(SkIntToScalar(120), 0);
        }
    }

private:
    typedef GM INHERITED;
};

/*
 Inspired by this <canvas> javascript, where we need to detect that we are not
 solving a quadratic equation, but must instead solve a linear (since our X^2
 coefficient is 0)

 ctx.fillStyle = '#f00';
 ctx.fillRect(0, 0, 100, 50);

 var g = ctx.createRadialGradient(-80, 25, 70, 0, 25, 150);
 g.addColorStop(0, '#f00');
 g.addColorStop(0.01, '#0f0');
 g.addColorStop(0.99, '#0f0');
 g.addColorStop(1, '#f00');
 ctx.fillStyle = g;
 ctx.fillRect(0, 0, 100, 50);
 */
class GradientsDegenrate2PointGM : public GM {
public:
    GradientsDegenrate2PointGM() {}

protected:
    SkString onShortName() {
        return SkString("gradients_degenerate_2pt");
    }

	virtual SkISize onISize() { return make_isize(320, 320); }

    void drawBG(SkCanvas* canvas) {
        canvas->drawColor(SK_ColorBLUE);
    }

    virtual void onDraw(SkCanvas* canvas) {
        this->drawBG(canvas);

        SkColor colors[] = { SK_ColorRED, SK_ColorGREEN, SK_ColorGREEN, SK_ColorRED };
        SkScalar pos[] = { 0, SkFloatToScalar(0.01f), SkFloatToScalar(0.99f), SK_Scalar1 };
        SkPoint c0;
        c0.iset(-80, 25);
        SkScalar r0 = SkIntToScalar(70);
        SkPoint c1;
        c1.iset(0, 25);
        SkScalar r1 = SkIntToScalar(150);
        SkShader* s = SkGradientShader::CreateTwoPointRadial(c0, r0, c1, r1, colors,
                                                             pos, SK_ARRAY_COUNT(pos),
                                                             SkShader::kClamp_TileMode);
        SkPaint paint;
        paint.setShader(s)->unref();
        canvas->drawPaint(paint);
    }

private:
    typedef GM INHERITED;
};

/// Tests correctness of *optimized* codepaths in gradients.

class ClampedGradientsGM : public GM {
public:
    ClampedGradientsGM() {}

protected:
    SkString onShortName() { return SkString("clamped_gradients"); }

    virtual SkISize onISize() { return make_isize(640, 510); }

    void drawBG(SkCanvas* canvas) {
        canvas->drawColor(0xFFDDDDDD);
    }

    virtual void onDraw(SkCanvas* canvas) {
        this->drawBG(canvas);

        SkRect r = { 0, 0, SkIntToScalar(100), SkIntToScalar(300) };
        SkPaint paint;
        paint.setAntiAlias(true);

        SkPoint center;
        center.iset(0, 300);
        canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
        SkShader* shader = SkGradientShader::CreateRadial(
            SkPoint(center),
            200, gColors, NULL, 5,
            SkShader::kClamp_TileMode, NULL);
        paint.setShader(shader);
        canvas->drawRect(r, paint);
        shader->unref();
    }

private:
    typedef GM INHERITED;
};

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

static GM* MyFactory(void*) { return new GradientsGM; }
static GMRegistry reg(MyFactory);

static GM* MyFactory2(void*) { return new GradientsDegenrate2PointGM; }
static GMRegistry reg2(MyFactory2);

static GM* MyFactory3(void*) { return new ClampedGradientsGM; }
static GMRegistry reg3(MyFactory3);

}

<commit_msg>Fix clamped_gradients gm to work in fixed.<commit_after>
/*
 * Copyright 2011 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */
#include "gm.h"
#include "SkGradientShader.h"

namespace skiagm {

struct GradData {
    int             fCount;
    const SkColor*  fColors;
    const SkScalar* fPos;
};

static const SkColor gColors[] = {
    SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE, SK_ColorBLACK
};
static const SkScalar gPos0[] = { 0, SK_Scalar1 };
static const SkScalar gPos1[] = { SK_Scalar1/4, SK_Scalar1*3/4 };
static const SkScalar gPos2[] = {
    0, SK_Scalar1/8, SK_Scalar1/2, SK_Scalar1*7/8, SK_Scalar1
};

static const GradData gGradData[] = {
    { 2, gColors, NULL },
    { 2, gColors, gPos0 },
    { 2, gColors, gPos1 },
    { 5, gColors, NULL },
    { 5, gColors, gPos2 }
};

static SkShader* MakeLinear(const SkPoint pts[2], const GradData& data,
                            SkShader::TileMode tm, SkUnitMapper* mapper) {
    return SkGradientShader::CreateLinear(pts, data.fColors, data.fPos,
                                          data.fCount, tm, mapper);
}

static SkShader* MakeRadial(const SkPoint pts[2], const GradData& data,
                            SkShader::TileMode tm, SkUnitMapper* mapper) {
    SkPoint center;
    center.set(SkScalarAve(pts[0].fX, pts[1].fX),
               SkScalarAve(pts[0].fY, pts[1].fY));
    return SkGradientShader::CreateRadial(center, center.fX, data.fColors,
                                          data.fPos, data.fCount, tm, mapper);
}

static SkShader* MakeSweep(const SkPoint pts[2], const GradData& data,
                           SkShader::TileMode tm, SkUnitMapper* mapper) {
    SkPoint center;
    center.set(SkScalarAve(pts[0].fX, pts[1].fX),
               SkScalarAve(pts[0].fY, pts[1].fY));
    return SkGradientShader::CreateSweep(center.fX, center.fY, data.fColors,
                                         data.fPos, data.fCount, mapper);
}

static SkShader* Make2Radial(const SkPoint pts[2], const GradData& data,
                             SkShader::TileMode tm, SkUnitMapper* mapper) {
    SkPoint center0, center1;
    center0.set(SkScalarAve(pts[0].fX, pts[1].fX),
                SkScalarAve(pts[0].fY, pts[1].fY));
    center1.set(SkScalarInterp(pts[0].fX, pts[1].fX, SkIntToScalar(3)/5),
                SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4));
    return SkGradientShader::CreateTwoPointRadial(
                                                  center1, (pts[1].fX - pts[0].fX) / 7,
                                                  center0, (pts[1].fX - pts[0].fX) / 2,
                                                  data.fColors, data.fPos, data.fCount, tm, mapper);
}

typedef SkShader* (*GradMaker)(const SkPoint pts[2], const GradData& data,
                               SkShader::TileMode tm, SkUnitMapper* mapper);
static const GradMaker gGradMakers[] = {
    MakeLinear, MakeRadial, MakeSweep, Make2Radial
};

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

class GradientsGM : public GM {
public:
	GradientsGM() {}

protected:
    SkString onShortName() {
        return SkString("gradients");
    }

    virtual SkISize onISize() { return make_isize(640, 510); }

    void drawBG(SkCanvas* canvas) {
        canvas->drawColor(0xFFDDDDDD);
    }

    virtual void onDraw(SkCanvas* canvas) {
        this->drawBG(canvas);

        SkPoint pts[2] = {
            { 0, 0 },
            { SkIntToScalar(100), SkIntToScalar(100) }
        };
        SkShader::TileMode tm = SkShader::kClamp_TileMode;
        SkRect r = { 0, 0, SkIntToScalar(100), SkIntToScalar(100) };
        SkPaint paint;
        paint.setAntiAlias(true);

        canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
        for (size_t i = 0; i < SK_ARRAY_COUNT(gGradData); i++) {
            canvas->save();
            for (size_t j = 0; j < SK_ARRAY_COUNT(gGradMakers); j++) {
                SkShader* shader = gGradMakers[j](pts, gGradData[i], tm, NULL);
                paint.setShader(shader);
                canvas->drawRect(r, paint);
                shader->unref();
                canvas->translate(0, SkIntToScalar(120));
            }
            canvas->restore();
            canvas->translate(SkIntToScalar(120), 0);
        }
    }

private:
    typedef GM INHERITED;
};

/*
 Inspired by this <canvas> javascript, where we need to detect that we are not
 solving a quadratic equation, but must instead solve a linear (since our X^2
 coefficient is 0)

 ctx.fillStyle = '#f00';
 ctx.fillRect(0, 0, 100, 50);

 var g = ctx.createRadialGradient(-80, 25, 70, 0, 25, 150);
 g.addColorStop(0, '#f00');
 g.addColorStop(0.01, '#0f0');
 g.addColorStop(0.99, '#0f0');
 g.addColorStop(1, '#f00');
 ctx.fillStyle = g;
 ctx.fillRect(0, 0, 100, 50);
 */
class GradientsDegenrate2PointGM : public GM {
public:
    GradientsDegenrate2PointGM() {}

protected:
    SkString onShortName() {
        return SkString("gradients_degenerate_2pt");
    }

	virtual SkISize onISize() { return make_isize(320, 320); }

    void drawBG(SkCanvas* canvas) {
        canvas->drawColor(SK_ColorBLUE);
    }

    virtual void onDraw(SkCanvas* canvas) {
        this->drawBG(canvas);

        SkColor colors[] = { SK_ColorRED, SK_ColorGREEN, SK_ColorGREEN, SK_ColorRED };
        SkScalar pos[] = { 0, SkFloatToScalar(0.01f), SkFloatToScalar(0.99f), SK_Scalar1 };
        SkPoint c0;
        c0.iset(-80, 25);
        SkScalar r0 = SkIntToScalar(70);
        SkPoint c1;
        c1.iset(0, 25);
        SkScalar r1 = SkIntToScalar(150);
        SkShader* s = SkGradientShader::CreateTwoPointRadial(c0, r0, c1, r1, colors,
                                                             pos, SK_ARRAY_COUNT(pos),
                                                             SkShader::kClamp_TileMode);
        SkPaint paint;
        paint.setShader(s)->unref();
        canvas->drawPaint(paint);
    }

private:
    typedef GM INHERITED;
};

/// Tests correctness of *optimized* codepaths in gradients.

class ClampedGradientsGM : public GM {
public:
    ClampedGradientsGM() {}

protected:
    SkString onShortName() { return SkString("clamped_gradients"); }

    virtual SkISize onISize() { return make_isize(640, 510); }

    void drawBG(SkCanvas* canvas) {
        canvas->drawColor(0xFFDDDDDD);
    }

    virtual void onDraw(SkCanvas* canvas) {
        this->drawBG(canvas);

        SkRect r = { 0, 0, SkIntToScalar(100), SkIntToScalar(300) };
        SkPaint paint;
        paint.setAntiAlias(true);

        SkPoint center;
        center.iset(0, 300);
        canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
        SkShader* shader = SkGradientShader::CreateRadial(
            SkPoint(center),
            SkIntToScalar(200), gColors, NULL, 5,
            SkShader::kClamp_TileMode, NULL);
        paint.setShader(shader);
        canvas->drawRect(r, paint);
        shader->unref();
    }

private:
    typedef GM INHERITED;
};

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

static GM* MyFactory(void*) { return new GradientsGM; }
static GMRegistry reg(MyFactory);

static GM* MyFactory2(void*) { return new GradientsDegenrate2PointGM; }
static GMRegistry reg2(MyFactory2);

static GM* MyFactory3(void*) { return new ClampedGradientsGM; }
static GMRegistry reg3(MyFactory3);

}

<|endoftext|>