<commit_before>// Copyright 2014 kloudkl@github

#include <fstream> // for std::ofstream
#include <queue> // for std::priority_queue
#include <cuda_runtime.h>
#include <google/protobuf/text_format.h>

#include "caffe/blob.hpp"
#include "caffe/common.hpp"
#include "caffe/vision_layers.hpp"
#include "caffe/net.hpp"
#include "caffe/proto/caffe.pb.h"
#include "caffe/util/io.hpp"
#include "caffe/util/math_functions.hpp"

using namespace caffe;

template<typename Dtype>
void similarity_search(
    const vector<shared_ptr<Blob<Dtype> > >& sample_binary_feature_blobs,
    const shared_ptr<Blob<Dtype> > query_binary_feature,
    const int top_k_results, shared_ptr<Blob<Dtype> > retrieval_results);

template<typename Dtype>
int image_retrieval_pipeline(int argc, char** argv);

int main(int argc, char** argv) {
  return image_retrieval_pipeline<float>(argc, argv);
//  return image_retrieval_pipeline<double>(argc, argv);
}

template<typename Dtype>
int image_retrieval_pipeline(int argc, char** argv) {
  const int num_required_args = 4;
  if (argc < num_required_args) {
    LOG(ERROR)<<
    "This program takes in binarized features of query images and sample images"
    "  extracted by Caffe to retrieve similar images."
    "Usage: demo_retrieve_images  sample_binary_features_binaryproto_file"
    "  query_binary_features_binaryproto_file  save_retrieval_result_filename"
    "  [top_k_results=1]  [CPU/GPU]  [DEVICE_ID=0]";
    return 1;
  }
  int arg_pos = num_required_args;

  int top_k_results;
  if (argc <= num_required_args) {
    top_k_results = 1;
  } else {
    top_k_results = atoi(argv[arg_pos]);
    CHECK_GE(top_k_results, 0);
  }

  arg_pos = num_required_args + 1;
  if (argc > arg_pos && strcmp(argv[arg_pos], "GPU") == 0) {
    LOG(ERROR)<< "Using GPU";
    uint device_id = 0;
    if (argc > arg_pos + 1) {
      device_id = atoi(argv[arg_pos + 1]);
    }
    LOG(ERROR) << "Using Device_id=" << device_id;
    Caffe::SetDevice(device_id);
    Caffe::set_mode(Caffe::GPU);
  } else {
    LOG(ERROR) << "Using CPU";
    Caffe::set_mode(Caffe::CPU);
  }
  Caffe::set_phase(Caffe::TEST);

  NetParameter pretrained_net_param;

  arg_pos = 0;  // the name of the executable

  string sample_binary_features_binaryproto_file(argv[++arg_pos]);
  BlobProtoVector sample_binary_features;
  ReadProtoFromBinaryFile(sample_binary_features_binaryproto_file,
                          &sample_binary_features);
  vector<shared_ptr<Blob<Dtype> > > sample_binary_feature_blobs;
  int num_samples;
  for (int i = 0; i < sample_binary_features.blobs_size(); ++i) {
    shared_ptr<Blob<Dtype> > blob(new Blob<Dtype>());
    blob->FromProto(sample_binary_features.blobs(i));
    sample_binary_feature_blobs.push_back(blob);
    num_samples += blob->num();
  }
  if (top_k_results > num_samples) {
    top_k_results = num_samples;
  }

  string query_images_feature_blob_binaryproto(argv[++arg_pos]);
  BlobProtoVector query_images_features;
  ReadProtoFromBinaryFile(query_images_feature_blob_binaryproto,
                          &query_images_features);
  vector<shared_ptr<Blob<Dtype> > > query_binary_feature_blobs;
  for (int i = 0; i < sample_binary_features.blobs_size(); ++i) {
    shared_ptr<Blob<Dtype> > blob(new Blob<Dtype>());
    blob->FromProto(query_images_features.blobs(i));
    query_binary_feature_blobs.push_back(blob);
  }

  string save_retrieval_result_filename(argv[++arg_pos]);
  std::ofstream retrieval_result_ofs(save_retrieval_result_filename.c_str(),
                                     std::ofstream::out);

  LOG(ERROR)<< "Retrieving images";
  shared_ptr<Blob<Dtype> > retrieval_results;
  int query_image_index = 0;

  int num_bytes_of_binary_code = sizeof(Dtype);
  int num_query_batches = query_binary_feature_blobs.size();
  for (int batch_index = 0; batch_index < num_query_batches; ++batch_index) {
    LOG(ERROR)<< "Batch " << batch_index << " image retrieval";
    similarity_search<Dtype>(sample_binary_feature_blobs,
        query_binary_feature_blobs[batch_index],
        top_k_results, retrieval_results);

    LOG(ERROR) << "Batch " << batch_index << " save image retrieval results";
    int num_results = retrieval_results->num();
    const Dtype* retrieval_results_data = retrieval_results->cpu_data();
    for (int i = 0; i < num_results; ++i) {
      retrieval_result_ofs << ++query_image_index;
      retrieval_results_data += retrieval_results->offset(i);
      for (int j = 0; j < top_k_results; ++j) {
        retrieval_result_ofs << " " << retrieval_results_data[j];
      }
      retrieval_result_ofs << "\n";
    }
  }  //  for (int batch_index = 0; batch_index < num_query_batches; ++batch_index) {

  retrieval_result_ofs.close();
  LOG(ERROR)<< "Successfully ended!";
  return 0;
}

template<typename Dtype>
void binarize(const int n, const Dtype* real_valued_feature,
              Dtype* binary_codes) {
  // TODO: more advanced binarization algorithm such as bilinear projection
  // Yunchao Gong, Sanjiv Kumar, Henry A. Rowley, and Svetlana Lazebnik.
  // Learning Binary Codes for High-Dimensional Data Using Bilinear Projections.
  // In IEEE International Conference on Computer Vision and Pattern Recognition (CVPR), 2013.
  // http://www.unc.edu/~yunchao/bpbc.htm
  int size_of_code = sizeof(Dtype) * 8;
  CHECK_EQ(n % size_of_code, 0);
  int num_binary_codes = n / size_of_code;
  uint64_t code;
  int offset;
  for (int i = 0; i < num_binary_codes; ++i) {
    code = 0;
    offset = i * size_of_code;
    for (int j = 0; j < size_of_code; ++j) {
      code |= sign(real_valued_feature[offset + j]);
      code << 1;
    }
    binary_codes[i] = static_cast<Dtype>(code);
  }
}

template<typename Dtype>
void binarize(const shared_ptr<Blob<Dtype> > real_valued_features,
              shared_ptr<Blob<Dtype> > binary_codes) {
  int num = real_valued_features->num();
  int dim = real_valued_features->count() / num;
  int size_of_code = sizeof(Dtype) * 8;
  CHECK_EQ(dim % size_of_code, 0);
  binary_codes->Reshape(num, dim / size_of_code, 1, 1);
  const Dtype* real_valued_features_data = real_valued_features->cpu_data();
  Dtype* binary_codes_data = binary_codes->mutable_cpu_data();
  for (int n = 0; n < num; ++n) {
    binarize<Dtype>(dim,
                    real_valued_features_data + real_valued_features->offset(n),
                    binary_codes_data + binary_codes->offset(n));
  }
}

class MinHeapComparison {
 public:
  bool operator()(const std::pair<int, int>& lhs,
                  const std::pair<int, int>&rhs) const {
    return (lhs.first > rhs.first);
  }
};

template<typename Dtype>
void similarity_search(
    const vector<shared_ptr<Blob<Dtype> > >& sample_images_feature_blobs,
    const shared_ptr<Blob<Dtype> > query_image_feature, const int top_k_results,
    shared_ptr<Blob<Dtype> > retrieval_results) {
  int num_queries = query_image_feature->num();
  int dim = query_image_feature->count() / num_queries;
  int hamming_dist;
  retrieval_results->Reshape(num_queries, top_k_results, 1, 1);
  Dtype* retrieval_results_data = retrieval_results->mutable_cpu_data();
  for (int i = 0; i < num_queries; ++i) {
    std::priority_queue<std::pair<int, int>,
        std::vector<std::pair<int, int> >, MinHeapComparison> results;
    for (int num_sample_blob;
        num_sample_blob < sample_images_feature_blobs.size();
        ++num_sample_blob) {
      shared_ptr<Blob<Dtype> > sample_images_feature =
          sample_images_feature_blobs[num_sample_blob];
      int num_samples = sample_images_feature->num();
      for (int j = 0; j < num_samples; ++j) {
        hamming_dist = caffe_hamming_distance(
            dim,
            query_image_feature->cpu_data() + query_image_feature->offset(i),
            sample_images_feature->cpu_data()
                + sample_images_feature->offset(j));
        if (results.size() < top_k_results) {
          results.push(std::make_pair(-hamming_dist, j));
        } else if (-hamming_dist > results.top().first) {  // smaller hamming dist
          results.pop();
          results.push(std::make_pair(-hamming_dist, j));
        }
      }  // for (int j = 0; j < num_samples; ++j) {
      retrieval_results_data += retrieval_results->offset(i);
      for (int k = 0; k < results.size(); ++k) {
        retrieval_results_data[k] = results.top().second;
        results.pop();
      }
    } // for(...; sample_images_feature_blobs.size(); ...)
  } // for (int i = 0; i < num_queries; ++i) {
}
<commit_msg>Fix bugs in the image retrieval example<commit_after>// Copyright 2014 kloudkl@github

#include <fstream> // for std::ofstream
#include <queue> // for std::priority_queue
#include <cuda_runtime.h>
#include <google/protobuf/text_format.h>

#include "caffe/blob.hpp"
#include "caffe/common.hpp"
#include "caffe/vision_layers.hpp"
#include "caffe/net.hpp"
#include "caffe/proto/caffe.pb.h"
#include "caffe/util/io.hpp"
#include "caffe/util/math_functions.hpp"

using namespace caffe;

template<typename Dtype>
void similarity_search(
    const vector<shared_ptr<Blob<Dtype> > >& sample_binary_feature_blobs,
    const shared_ptr<Blob<Dtype> > query_binary_feature,
    const int top_k_results, vector<vector<Dtype> >* retrieval_results);

template<typename Dtype>
int image_retrieval_pipeline(int argc, char** argv);

int main(int argc, char** argv) {
  return image_retrieval_pipeline<float>(argc, argv);
//  return image_retrieval_pipeline<double>(argc, argv);
}

template<typename Dtype>
int image_retrieval_pipeline(int argc, char** argv) {
  const int num_required_args = 4;
  if (argc < num_required_args) {
    LOG(ERROR)<<
    "This program takes in binarized features of query images and sample images"
    " extracted by Caffe to retrieve similar images.\n"
    "Usage: demo_retrieve_images  sample_binary_features_binaryproto_file"
    "  query_binary_features_binaryproto_file  save_retrieval_result_filename"
    "  [top_k_results=1]  [CPU/GPU]  [DEVICE_ID=0]";
    return 1;
  }
  int arg_pos = num_required_args;

  int top_k_results;
  if (argc <= num_required_args) {
    top_k_results = 1;
  } else {
    top_k_results = atoi(argv[arg_pos]);
    CHECK_GE(top_k_results, 0);
  }

  arg_pos = num_required_args + 1;
  if (argc > arg_pos && strcmp(argv[arg_pos], "GPU") == 0) {
    LOG(ERROR)<< "Using GPU";
    uint device_id = 0;
    if (argc > arg_pos + 1) {
      device_id = atoi(argv[arg_pos + 1]);
    }
    LOG(ERROR) << "Using Device_id=" << device_id;
    Caffe::SetDevice(device_id);
    Caffe::set_mode(Caffe::GPU);
  } else {
    LOG(ERROR) << "Using CPU";
    Caffe::set_mode(Caffe::CPU);
  }
  Caffe::set_phase(Caffe::TEST);

  arg_pos = 0;  // the name of the executable

  LOG(ERROR)<< "Loading sample binary features";
  string sample_binary_features_binaryproto_file(argv[++arg_pos]);
  BlobProtoVector sample_binary_features;
  ReadProtoFromBinaryFile(sample_binary_features_binaryproto_file,
                          &sample_binary_features);
  vector<shared_ptr<Blob<Dtype> > > sample_binary_feature_blobs;
  int num_samples;
  for (int i = 0; i < sample_binary_features.blobs_size(); ++i) {
    shared_ptr<Blob<Dtype> > blob(new Blob<Dtype>());
    blob->FromProto(sample_binary_features.blobs(i));
    sample_binary_feature_blobs.push_back(blob);
    num_samples += blob->num();
  }
  if (top_k_results > num_samples) {
    top_k_results = num_samples;
  }

  LOG(ERROR)<< "Loading query binary features";
  string query_images_feature_blob_binaryproto(argv[++arg_pos]);
  BlobProtoVector query_images_features;
  ReadProtoFromBinaryFile(query_images_feature_blob_binaryproto,
                          &query_images_features);
  vector<shared_ptr<Blob<Dtype> > > query_binary_feature_blobs;
  for (int i = 0; i < query_images_features.blobs_size(); ++i) {
    shared_ptr<Blob<Dtype> > blob(new Blob<Dtype>());
    blob->FromProto(query_images_features.blobs(i));
    query_binary_feature_blobs.push_back(blob);
  }

  string save_retrieval_result_filename(argv[++arg_pos]);
  LOG(ERROR)<< "Opening result file " << save_retrieval_result_filename;
  std::ofstream retrieval_result_ofs(save_retrieval_result_filename.c_str(),
                                     std::ofstream::out);

  LOG(ERROR)<< "Retrieving images";
  vector<vector<Dtype> > retrieval_results;
  int query_image_index = 0;

  int num_query_batches = query_binary_feature_blobs.size();
  for (int batch_index = 0; batch_index < num_query_batches; ++batch_index) {
    similarity_search<Dtype>(sample_binary_feature_blobs,
                             query_binary_feature_blobs[batch_index],
                             top_k_results, &retrieval_results);
    int num_results = retrieval_results.size();
    for (int i = 0; i < num_results; ++i) {
      retrieval_result_ofs << query_image_index++;
      for (int j = 0; j < retrieval_results[i].size(); ++j) {
        retrieval_result_ofs << " " << retrieval_results[i][j];
      }
      retrieval_result_ofs << "\n";
    }
  }  //  for (int batch_index = 0; batch_index < num_query_batches; ++batch_index) {

  retrieval_result_ofs.close();
  LOG(ERROR)<< "Successfully retrieved similar images for " << query_image_index << " queries!";
  return 0;
}

class MinHeapComparison {
 public:
  bool operator()(const std::pair<int, int>& lhs,
                  const std::pair<int, int>&rhs) const {
    return (lhs.first > rhs.first);
  }
};

template<typename Dtype>
void similarity_search(
    const vector<shared_ptr<Blob<Dtype> > >& sample_images_feature_blobs,
    const shared_ptr<Blob<Dtype> > query_image_feature, const int top_k_results,
    vector<vector<Dtype> >* retrieval_results) {
  int num_queries = query_image_feature->num();
  int dim = query_image_feature->count() / num_queries;
  int hamming_dist;
  retrieval_results->resize(num_queries);
  std::priority_queue<std::pair<int, int>, std::vector<std::pair<int, int> >,
      MinHeapComparison> results;
  for (int i = 0; i < num_queries; ++i) {
    while (!results.empty()) {
      results.pop();
    }
    for (int j = 0; j < sample_images_feature_blobs.size(); ++j) {
      int num_samples = sample_images_feature_blobs[j]->num();
      for (int k = 0; k < num_samples; ++k) {
        hamming_dist = caffe_hamming_distance(
            dim,
            query_image_feature->cpu_data() + query_image_feature->offset(i),
            sample_images_feature_blobs[j]->cpu_data()
                + sample_images_feature_blobs[j]->offset(k));
        if (results.size() < top_k_results) {
          results.push(std::make_pair(-hamming_dist, k));
        } else if (-hamming_dist > results.top().first) {  // smaller hamming dist
          results.pop();
          results.push(std::make_pair(-hamming_dist, k));
        }
      }  // for (int k = 0; k < num_samples; ++k) {
    }  // for (int j = 0; j < sample_images_feature_blobs.size(); ++j)
    retrieval_results->at(i).resize(results.size());
    for (int k = results.size() - 1; k >= 0; --k) {
      retrieval_results->at(i)[k] = results.top().second;
      results.pop();
    }
  }  // for (int i = 0; i < num_queries; ++i) {
}
<|endoftext|>


<commit_before>// This file is a part of the IncludeOS unikernel - www.includeos.org
//
// Copyright 2015 Oslo and Akershus University College of Applied Sciences
// and Alfred Bratterud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <os>
#include <net/inet4>
#include <net/dhcp/dh4client.hpp>
#include <math.h> // rand()
#include <sstream>

// An IP-stack object
std::unique_ptr<net::Inet4<VirtioNet> > inet;

using namespace std::chrono;

std::string HTML_RESPONSE() {
  int color = rand();
  std::stringstream stream;

  /* HTML Fonts */
  std::string ubuntu_medium  = "font-family: \'Ubuntu\', sans-serif; font-weight: 500; ";
  std::string ubuntu_normal  = "font-family: \'Ubuntu\', sans-serif; font-weight: 400; ";
  std::string ubuntu_light  = "font-family: \'Ubuntu\', sans-serif; font-weight: 300; ";

  /* HTML */
  stream << ""
         << "<link href='https://fonts.googleapis.com/css?family=Ubuntu:500,300' rel='stylesheet' type='text/css'>"
         << ""
         << "<h1 style= \"color: " << "#" << std::hex << (color >> 8) << "\">"
         <<  "IncludeOS
"
         <<  "
Now speaks TCP!
"
    // .... generate more dynamic content
         << "
  ...and can improvise http. With limitations of course, but it's been easier than expected so far
"
         << "
 © 2015, Oslo and Akershus University College of Applied Sciences "
         << "\n";

  std::string html = stream.str();

  std::string header="HTTP/1.1 200 OK \n "        \
    "Date: Mon, 01 Jan 1970 00:00:01 GMT \n"      \
    "Server: IncludeOS prototype 4.0 \n"        \
    "Last-Modified: Wed, 08 Jan 2003 23:11:55 GMT \n"   \
    "Content-Type: text/html; charset=UTF-8 \n"     \
    "Content-Length: "+std::to_string(html.size())+"\n"   \
    "Accept-Ranges: bytes\n"          \
    "Connection: close\n\n";
  return header + html;
}

void Service::start() {
  // Assign a driver (VirtioNet) to a network interface (eth0)
  // @note: We could determine the appropirate driver dynamically, but then we'd
  // have to include all the drivers into the image, which  we want to avoid.
  hw::Nic<VirtioNet>& eth0 = hw::Dev::eth<0,VirtioNet>();

  // Bring up a network stack, attached to the nic
  // @note : No parameters after 'nic' means we'll use DHCP for IP config.
  inet = std::make_unique<net::Inet4<VirtioNet> >(eth0);

  // Static IP configuration, until we (possibly) get DHCP
  // @note : Mostly to get a robust demo service that it works with and without DHCP
  inet->network_config( {{ 10,0,0,42 }},      // IP
                        {{ 255,255,255,0 }},  // Netmask
                        {{ 10,0,0,1 }},       // Gateway
                        {{ 8,8,8,8 }} );      // DNS

  srand(OS::cycles_since_boot());

  // Set up a TCP server on port 80
  auto& server = inet->tcp().bind(80);

  hw::PIT::instance().onRepeatedTimeout(30s, []{
      printf("<Service> TCP STATUS:\n%s \n", inet->tcp().status().c_str());
    });

  // Add a TCP connection handler - here a hardcoded HTTP-service
  server.onAccept([](auto conn) -> bool {
      printf("<Service> @onAccept - Connection attempt from: %s \n",
             conn->to_string().c_str());
      return true; // allow all connections

    }).onConnect([](auto conn) {
        printf("<Service> @onConnect - Connection successfully established.\n");
        // read async with a buffer size of 1024 bytes
        // define what to do when data is read
        conn->read(1024, [conn](net::TCP::buffer_t buf, size_t n) {
            // create string from buffer
            std::string data { (char*)buf.get(), n };
            printf("<Service> @read:\n%s\n", data.c_str());

            // create response
            std::string response = HTML_RESPONSE();
            // write the data from the string with the strings size
            conn->write(response.data(), response.size(), [](size_t n) {
                printf("<Service> @write: %u bytes written\n", n);
              });
          });

      }).onDisconnect([](auto, auto reason) {
          printf("<Service> @onDisconnect - Reason: %s \n", reason.to_string().c_str());
        });

  printf("*** TEST SERVICE STARTED *** \n");
}
<commit_msg>Fixed service.cpp to work with IP-constructor<commit_after>// This file is a part of the IncludeOS unikernel - www.includeos.org
//
// Copyright 2015 Oslo and Akershus University College of Applied Sciences
// and Alfred Bratterud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <os>
#include <net/inet4>
#include <net/dhcp/dh4client.hpp>
#include <math.h> // rand()
#include <sstream>

// An IP-stack object
std::unique_ptr<net::Inet4<VirtioNet> > inet;

using namespace std::chrono;

std::string HTML_RESPONSE() {
  int color = rand();
  std::stringstream stream;

  /* HTML Fonts */
  std::string ubuntu_medium  = "font-family: \'Ubuntu\', sans-serif; font-weight: 500; ";
  std::string ubuntu_normal  = "font-family: \'Ubuntu\', sans-serif; font-weight: 400; ";
  std::string ubuntu_light  = "font-family: \'Ubuntu\', sans-serif; font-weight: 300; ";

  /* HTML */
  stream << ""
         << "<link href='https://fonts.googleapis.com/css?family=Ubuntu:500,300' rel='stylesheet' type='text/css'>"
         << ""
         << "<h1 style= \"color: " << "#" << std::hex << (color >> 8) << "\">"
         <<  "IncludeOS
"
         <<  "
Now speaks TCP!
"
    // .... generate more dynamic content
         << "
  ...and can improvise http. With limitations of course, but it's been easier than expected so far
"
         << "
 © 2015, Oslo and Akershus University College of Applied Sciences "
         << "\n";

  std::string html = stream.str();

  std::string header="HTTP/1.1 200 OK \n "        \
    "Date: Mon, 01 Jan 1970 00:00:01 GMT \n"      \
    "Server: IncludeOS prototype 4.0 \n"        \
    "Last-Modified: Wed, 08 Jan 2003 23:11:55 GMT \n"   \
    "Content-Type: text/html; charset=UTF-8 \n"     \
    "Content-Length: "+std::to_string(html.size())+"\n"   \
    "Accept-Ranges: bytes\n"          \
    "Connection: close\n\n";
  return header + html;
}

void Service::start() {
  // Assign a driver (VirtioNet) to a network interface (eth0)
  // @note: We could determine the appropirate driver dynamically, but then we'd
  // have to include all the drivers into the image, which  we want to avoid.
  hw::Nic<VirtioNet>& eth0 = hw::Dev::eth<0,VirtioNet>();

  // Bring up a network stack, attached to the nic
  // @note : No parameters after 'nic' means we'll use DHCP for IP config.
  inet = std::make_unique<net::Inet4<VirtioNet> >(eth0);

  // Static IP configuration, until we (possibly) get DHCP
  // @note : Mostly to get a robust demo service that it works with and without DHCP
  inet->network_config( { 10,0,0,42 },      // IP
                        { 255,255,255,0 },  // Netmask
                        { 10,0,0,1 },       // Gateway
                        { 8,8,8,8 } );      // DNS

  srand(OS::cycles_since_boot());

  // Set up a TCP server on port 80
  auto& server = inet->tcp().bind(80);

  hw::PIT::instance().onRepeatedTimeout(30s, []{
      printf("<Service> TCP STATUS:\n%s \n", inet->tcp().status().c_str());
    });

  // Add a TCP connection handler - here a hardcoded HTTP-service
  server.onAccept([](auto conn) -> bool {
      printf("<Service> @onAccept - Connection attempt from: %s \n",
             conn->to_string().c_str());
      return true; // allow all connections

    }).onConnect([](auto conn) {
        printf("<Service> @onConnect - Connection successfully established.\n");
        // read async with a buffer size of 1024 bytes
        // define what to do when data is read
        conn->read(1024, [conn](net::TCP::buffer_t buf, size_t n) {
            // create string from buffer
            std::string data { (char*)buf.get(), n };
            printf("<Service> @read:\n%s\n", data.c_str());

            // create response
            std::string response = HTML_RESPONSE();
            // write the data from the string with the strings size
            conn->write(response.data(), response.size(), [](size_t n) {
                printf("<Service> @write: %u bytes written\n", n);
              });
          });

      }).onDisconnect([](auto, auto reason) {
          printf("<Service> @onDisconnect - Reason: %s \n", reason.to_string().c_str());
        });

  printf("*** TEST SERVICE STARTED *** \n");
}
<|endoftext|>


<commit_before>#pragma once

#include <string>
#include <vector>

namespace blobs
{

enum OpenFlags
{
    read = (1 << 0),
    write = (1 << 1),
    /* bits 3-7 reserved. */
    /* bits 8-15 given blob-specific definitions */
};

enum StateFlags
{
    open_read = (1 << 0),
    open_write = (1 << 1),
    committing = (1 << 2),
    committed = (1 << 3),
    commit_error = (1 << 4),
};

struct BlobMeta
{
    uint16_t blobState;
    uint32_t size;
    std::vector<uint8_t> metadata;
};

/*
 * All blob specific objects implement this interface.
 */
class GenericBlobInterface
{
  public:
    virtual ~GenericBlobInterface() = default;

    /**
     * Checks if the handler will manage this file path.
     *
     * @param[in] blobId.
     * @return bool whether it will manage the file path.
     */
    virtual bool canHandleBlob(const std::string& path) = 0;

    /**
     * Return the name(s) of the blob(s).  Used during GetCount.
     *
     * @return List of blobIds this handler manages.
     */
    virtual std::vector<std::string> getBlobIds() = 0;

    /**
     * Attempt to delete the blob specified by the path.
     *
     * @param[in] path - the blobId to try and delete.
     * @return bool - whether it was able to delete the blob.
     */
    virtual bool deleteBlob(const std::string& path) = 0;

    /**
     * Return metadata about the blob.
     *
     * @param[in] path - the blobId for metadata.
     * @param[in,out] meta - a pointer to a blobmeta.
     * @return bool - true if it was successful.
     */
    virtual bool stat(const std::string& path, struct BlobMeta* meta) = 0;

    /* The methods below are per session. */

    /**
     * Attempt to open a session from this path.
     *
     * @param[in] session - the session id.
     * @param[in] flags - the open flags.
     * @param[in] path - the blob path.
     * @return bool - was able to open the session.
     */
    virtual bool open(uint16_t session, uint16_t flags,
                      const std::string& path) = 0;

    /**
     * Attempt to read from a blob.
     *
     * @param[in] session - the session id.
     * @param[in] offset - offset into the blob.
     * @param[in] requestedSize - number of bytes to read.
     * @return Bytes read back (0 length on error).
     */
    virtual std::vector<uint8_t> read(uint16_t session, uint32_t offset,
                                      uint32_t requestedSize) = 0;

    /**
     * Attempt to write to a blob.
     *
     * @param[in] session - the session id.
     * @param[in] offset - offset into the blob.
     * @param[in] data - the data to write.
     * @return bool - was able to write.
     */
    virtual bool write(uint16_t session, uint32_t offset,
                       const std::vector<uint8_t>& data) = 0;

    /**
     * Attempt to write metadata to a blob.
     *
     * @param[in] session - the session id.
     * @param[in] offset - offset into the blob.
     * @param[in] data - the data to write.
     * @return bool - was able to write.
     */
    virtual bool writeMeta(uint16_t session, uint32_t offset,
                           const std::vector<uint8_t>& data) = 0;

    /**
     * Attempt to commit to a blob.
     *
     * @param[in] session - the session id.
     * @param[in] data - optional commit data.
     * @return bool - was able to start commit.
     */
    virtual bool commit(uint16_t session, const std::vector<uint8_t>& data) = 0;

    /**
     * Attempt to close your session.
     *
     * @param[in] session - the session id.
     * @return bool - was able to close session.
     */
    virtual bool close(uint16_t session) = 0;

    /**
     * Attempt to return metadata for the session's view of the blob.
     *
     * @param[in] session - the session id.
     * @param[in,out] meta - pointer to update with the BlobMeta.
     * @return bool - wether it was successful.
     */
    virtual bool stat(uint16_t session, struct BlobMeta* meta) = 0;

    /**
     * Attempt to expire a session.  This is called when a session has been
     * inactive for at least 10 minutes.
     *
     * @param[in] session - the session id.
     * @return bool - whether the session was able to be closed.
     */
    virtual bool expire(uint16_t session) = 0;
};
} // namespace blobs
<commit_msg>blobs-ipmid: blobs header: add prototype all handlers need<commit_after>#pragma once

#include <memory>
#include <string>
#include <vector>

namespace blobs
{

enum OpenFlags
{
    read = (1 << 0),
    write = (1 << 1),
    /* bits 3-7 reserved. */
    /* bits 8-15 given blob-specific definitions */
};

enum StateFlags
{
    open_read = (1 << 0),
    open_write = (1 << 1),
    committing = (1 << 2),
    committed = (1 << 3),
    commit_error = (1 << 4),
};

struct BlobMeta
{
    uint16_t blobState;
    uint32_t size;
    std::vector<uint8_t> metadata;
};

/*
 * All blob specific objects implement this interface.
 */
class GenericBlobInterface
{
  public:
    virtual ~GenericBlobInterface() = default;

    /**
     * Checks if the handler will manage this file path.
     *
     * @param[in] blobId.
     * @return bool whether it will manage the file path.
     */
    virtual bool canHandleBlob(const std::string& path) = 0;

    /**
     * Return the name(s) of the blob(s).  Used during GetCount.
     *
     * @return List of blobIds this handler manages.
     */
    virtual std::vector<std::string> getBlobIds() = 0;

    /**
     * Attempt to delete the blob specified by the path.
     *
     * @param[in] path - the blobId to try and delete.
     * @return bool - whether it was able to delete the blob.
     */
    virtual bool deleteBlob(const std::string& path) = 0;

    /**
     * Return metadata about the blob.
     *
     * @param[in] path - the blobId for metadata.
     * @param[in,out] meta - a pointer to a blobmeta.
     * @return bool - true if it was successful.
     */
    virtual bool stat(const std::string& path, struct BlobMeta* meta) = 0;

    /* The methods below are per session. */

    /**
     * Attempt to open a session from this path.
     *
     * @param[in] session - the session id.
     * @param[in] flags - the open flags.
     * @param[in] path - the blob path.
     * @return bool - was able to open the session.
     */
    virtual bool open(uint16_t session, uint16_t flags,
                      const std::string& path) = 0;

    /**
     * Attempt to read from a blob.
     *
     * @param[in] session - the session id.
     * @param[in] offset - offset into the blob.
     * @param[in] requestedSize - number of bytes to read.
     * @return Bytes read back (0 length on error).
     */
    virtual std::vector<uint8_t> read(uint16_t session, uint32_t offset,
                                      uint32_t requestedSize) = 0;

    /**
     * Attempt to write to a blob.
     *
     * @param[in] session - the session id.
     * @param[in] offset - offset into the blob.
     * @param[in] data - the data to write.
     * @return bool - was able to write.
     */
    virtual bool write(uint16_t session, uint32_t offset,
                       const std::vector<uint8_t>& data) = 0;

    /**
     * Attempt to write metadata to a blob.
     *
     * @param[in] session - the session id.
     * @param[in] offset - offset into the blob.
     * @param[in] data - the data to write.
     * @return bool - was able to write.
     */
    virtual bool writeMeta(uint16_t session, uint32_t offset,
                           const std::vector<uint8_t>& data) = 0;

    /**
     * Attempt to commit to a blob.
     *
     * @param[in] session - the session id.
     * @param[in] data - optional commit data.
     * @return bool - was able to start commit.
     */
    virtual bool commit(uint16_t session, const std::vector<uint8_t>& data) = 0;

    /**
     * Attempt to close your session.
     *
     * @param[in] session - the session id.
     * @return bool - was able to close session.
     */
    virtual bool close(uint16_t session) = 0;

    /**
     * Attempt to return metadata for the session's view of the blob.
     *
     * @param[in] session - the session id.
     * @param[in,out] meta - pointer to update with the BlobMeta.
     * @return bool - wether it was successful.
     */
    virtual bool stat(uint16_t session, struct BlobMeta* meta) = 0;

    /**
     * Attempt to expire a session.  This is called when a session has been
     * inactive for at least 10 minutes.
     *
     * @param[in] session - the session id.
     * @return bool - whether the session was able to be closed.
     */
    virtual bool expire(uint16_t session) = 0;
};
} // namespace blobs

#ifdef __cplusplus
extern "C" {
#endif

/**
 * All Blob handlers need to implement this method.  It is called after loading
 * the library to then get a handle to the blob handler.
 *
 * @return a unique pointer to your blob handler instance.
 */
std::unique_ptr<blobs::GenericBlobInterface> createHandler();

#ifdef __cplusplus
}
#endif
<|endoftext|>


<commit_before>//  Copyright (c) 2011-present, Facebook, Inc.  All rights reserved.
//  This source code is licensed under the BSD-style license found in the
//  LICENSE file in the root directory of this source tree. An additional grant
//  of patent rights can be found in the PATENTS file in the same directory.
//  This source code is also licensed under the GPLv2 license found in the
//  COPYING file in the root directory of this source tree.

#include "table/partitioned_filter_block.h"

#include <utility>

#include "port/port.h"
#include "rocksdb/filter_policy.h"
#include "table/block.h"
#include "table/block_based_table_reader.h"
#include "util/coding.h"

namespace rocksdb {

PartitionedFilterBlockBuilder::PartitionedFilterBlockBuilder(
    const SliceTransform* prefix_extractor, bool whole_key_filtering,
    FilterBitsBuilder* filter_bits_builder, int index_block_restart_interval,
    PartitionedIndexBuilder* const p_index_builder)
    : FullFilterBlockBuilder(prefix_extractor, whole_key_filtering,
                             filter_bits_builder),
      index_on_filter_block_builder_(index_block_restart_interval),
      p_index_builder_(p_index_builder) {}

PartitionedFilterBlockBuilder::~PartitionedFilterBlockBuilder() {}

void PartitionedFilterBlockBuilder::MaybeCutAFilterBlock() {
  if (!p_index_builder_->ShouldCutFilterBlock()) {
    return;
  }
  filter_gc.push_back(std::unique_ptr<const char[]>(nullptr));
  Slice filter = filter_bits_builder_->Finish(&filter_gc.back());
  std::string& index_key = p_index_builder_->GetPartitionKey();
  filters.push_back({index_key, filter});
}

void PartitionedFilterBlockBuilder::AddKey(const Slice& key) {
  MaybeCutAFilterBlock();
  filter_bits_builder_->AddKey(key);
}

Slice PartitionedFilterBlockBuilder::Finish(
    const BlockHandle& last_partition_block_handle, Status* status) {
  if (finishing_filters == true) {
    // Record the handle of the last written filter block in the index
    FilterEntry& last_entry = filters.front();
    std::string handle_encoding;
    last_partition_block_handle.EncodeTo(&handle_encoding);
    index_on_filter_block_builder_.Add(last_entry.key, handle_encoding);
    filters.pop_front();
  } else {
    MaybeCutAFilterBlock();
  }
  // If there is no filter partition left, then return the index on filter
  // partitions
  if (UNLIKELY(filters.empty())) {
    *status = Status::OK();
    if (finishing_filters) {
      return index_on_filter_block_builder_.Finish();
    } else {
      // This is the rare case where no key was added to the filter
      return Slice();
    }
  } else {
    // Return the next filter partition in line and set Incomplete() status to
    // indicate we expect more calls to Finish
    *status = Status::Incomplete();
    finishing_filters = true;
    return filters.front().filter;
  }
}

PartitionedFilterBlockReader::PartitionedFilterBlockReader(
    const SliceTransform* prefix_extractor, bool _whole_key_filtering,
    BlockContents&& contents, FilterBitsReader* filter_bits_reader,
    Statistics* stats, const Comparator& comparator,
    const BlockBasedTable* table)
    : FilterBlockReader(contents.data.size(), stats, _whole_key_filtering),
      prefix_extractor_(prefix_extractor),
      comparator_(comparator),
      table_(table) {
  idx_on_fltr_blk_.reset(new Block(std::move(contents),
                                   kDisableGlobalSequenceNumber,
                                   0 /* read_amp_bytes_per_bit */, stats));
}

PartitionedFilterBlockReader::~PartitionedFilterBlockReader() {
  {
    ReadLock rl(&mu_);
    for (auto it = handle_list_.begin(); it != handle_list_.end(); ++it) {
      table_->rep_->table_options.block_cache.get()->Release(*it);
    }
  }
  char cache_key[BlockBasedTable::kMaxCacheKeyPrefixSize + kMaxVarint64Length];
  for (auto it = filter_block_set_.begin(); it != filter_block_set_.end();
       ++it) {
    auto key = BlockBasedTable::GetCacheKey(table_->rep_->cache_key_prefix,
                                            table_->rep_->cache_key_prefix_size,
                                            *it, cache_key);
    table_->rep_->table_options.block_cache.get()->Erase(key);
  }
}

bool PartitionedFilterBlockReader::KeyMayMatch(
    const Slice& key, uint64_t block_offset, const bool no_io,
    const Slice* const const_ikey_ptr) {
  assert(const_ikey_ptr != nullptr);
  assert(block_offset == kNotValid);
  if (!whole_key_filtering_) {
    return true;
  }
  if (UNLIKELY(idx_on_fltr_blk_->size() == 0)) {
    return true;
  }
  auto filter_handle = GetFilterPartitionHandle(*const_ikey_ptr);
  if (UNLIKELY(filter_handle.size() == 0)) {  // key is out of range
    return false;
  }
  bool cached = false;
  auto filter_partition = GetFilterPartition(&filter_handle, no_io, &cached);
  if (UNLIKELY(!filter_partition.value)) {
    return true;
  }
  auto res = filter_partition.value->KeyMayMatch(key, block_offset, no_io);
  if (cached) {
    return res;
  }
  if (LIKELY(filter_partition.IsSet())) {
    filter_partition.Release(table_->rep_->table_options.block_cache.get());
  } else {
    delete filter_partition.value;
  }
  return res;
}

bool PartitionedFilterBlockReader::PrefixMayMatch(
    const Slice& prefix, uint64_t block_offset, const bool no_io,
    const Slice* const const_ikey_ptr) {
  assert(const_ikey_ptr != nullptr);
  assert(block_offset == kNotValid);
  if (!prefix_extractor_) {
    return true;
  }
  if (UNLIKELY(idx_on_fltr_blk_->size() == 0)) {
    return true;
  }
  auto filter_handle = GetFilterPartitionHandle(*const_ikey_ptr);
  if (UNLIKELY(filter_handle.size() == 0)) {  // prefix is out of range
    return false;
  }
  bool cached = false;
  auto filter_partition = GetFilterPartition(&filter_handle, no_io, &cached);
  if (UNLIKELY(!filter_partition.value)) {
    return true;
  }
  auto res = filter_partition.value->PrefixMayMatch(prefix, kNotValid, no_io);
  if (cached) {
    return res;
  }
  if (LIKELY(filter_partition.IsSet())) {
    filter_partition.Release(table_->rep_->table_options.block_cache.get());
  } else {
    delete filter_partition.value;
  }
  return res;
}

Slice PartitionedFilterBlockReader::GetFilterPartitionHandle(
    const Slice& entry) {
  BlockIter iter;
  idx_on_fltr_blk_->NewIterator(&comparator_, &iter, true);
  iter.Seek(entry);
  if (UNLIKELY(!iter.Valid())) {
    return Slice();
  }
  assert(iter.Valid());
  Slice handle_value = iter.value();
  return handle_value;
}

BlockBasedTable::CachableEntry<FilterBlockReader>
PartitionedFilterBlockReader::GetFilterPartition(Slice* handle_value,
                                                 const bool no_io,
                                                 bool* cached) {
  BlockHandle fltr_blk_handle;
  auto s = fltr_blk_handle.DecodeFrom(handle_value);
  assert(s.ok());
  const bool is_a_filter_partition = true;
  auto block_cache = table_->rep_->table_options.block_cache.get();
  if (LIKELY(block_cache != nullptr)) {
    bool pin_cached_filters =
        GetLevel() == 0 &&
        table_->rep_->table_options.pin_l0_filter_and_index_blocks_in_cache;
    if (pin_cached_filters) {
      ReadLock rl(&mu_);
      auto iter = filter_cache_.find(fltr_blk_handle.offset());
      if (iter != filter_cache_.end()) {
        RecordTick(statistics(), BLOCK_CACHE_FILTER_HIT);
        *cached = true;
        return {iter->second, nullptr};
      }
    }
    auto filter =
        table_->GetFilter(fltr_blk_handle, is_a_filter_partition, no_io);
    if (filter.IsSet()) {
      filter_block_set_.insert(fltr_blk_handle);
      if (pin_cached_filters) {
        WriteLock wl(&mu_);
        std::pair<uint64_t, FilterBlockReader*> pair(fltr_blk_handle.offset(),
                                                     filter.value);
        auto succ = filter_cache_.insert(pair).second;
        if (succ) {
          handle_list_.push_back(filter.cache_handle);
        }  // Otherwise it is already inserted by a concurrent thread
        *cached = true;
      }
    }
    return filter;
  } else {
    auto filter = table_->ReadFilter(fltr_blk_handle, is_a_filter_partition);
    return {filter, nullptr};
  }
}

size_t PartitionedFilterBlockReader::ApproximateMemoryUsage() const {
  return idx_on_fltr_blk_->size();
}

}  // namespace rocksdb
<commit_msg>Fix concurrency issue with filter_block_set_<commit_after>//  Copyright (c) 2011-present, Facebook, Inc.  All rights reserved.
//  This source code is licensed under the BSD-style license found in the
//  LICENSE file in the root directory of this source tree. An additional grant
//  of patent rights can be found in the PATENTS file in the same directory.
//  This source code is also licensed under the GPLv2 license found in the
//  COPYING file in the root directory of this source tree.

#include "table/partitioned_filter_block.h"

#include <utility>

#include "port/port.h"
#include "rocksdb/filter_policy.h"
#include "table/block.h"
#include "table/block_based_table_reader.h"
#include "util/coding.h"

namespace rocksdb {

PartitionedFilterBlockBuilder::PartitionedFilterBlockBuilder(
    const SliceTransform* prefix_extractor, bool whole_key_filtering,
    FilterBitsBuilder* filter_bits_builder, int index_block_restart_interval,
    PartitionedIndexBuilder* const p_index_builder)
    : FullFilterBlockBuilder(prefix_extractor, whole_key_filtering,
                             filter_bits_builder),
      index_on_filter_block_builder_(index_block_restart_interval),
      p_index_builder_(p_index_builder) {}

PartitionedFilterBlockBuilder::~PartitionedFilterBlockBuilder() {}

void PartitionedFilterBlockBuilder::MaybeCutAFilterBlock() {
  if (!p_index_builder_->ShouldCutFilterBlock()) {
    return;
  }
  filter_gc.push_back(std::unique_ptr<const char[]>(nullptr));
  Slice filter = filter_bits_builder_->Finish(&filter_gc.back());
  std::string& index_key = p_index_builder_->GetPartitionKey();
  filters.push_back({index_key, filter});
}

void PartitionedFilterBlockBuilder::AddKey(const Slice& key) {
  MaybeCutAFilterBlock();
  filter_bits_builder_->AddKey(key);
}

Slice PartitionedFilterBlockBuilder::Finish(
    const BlockHandle& last_partition_block_handle, Status* status) {
  if (finishing_filters == true) {
    // Record the handle of the last written filter block in the index
    FilterEntry& last_entry = filters.front();
    std::string handle_encoding;
    last_partition_block_handle.EncodeTo(&handle_encoding);
    index_on_filter_block_builder_.Add(last_entry.key, handle_encoding);
    filters.pop_front();
  } else {
    MaybeCutAFilterBlock();
  }
  // If there is no filter partition left, then return the index on filter
  // partitions
  if (UNLIKELY(filters.empty())) {
    *status = Status::OK();
    if (finishing_filters) {
      return index_on_filter_block_builder_.Finish();
    } else {
      // This is the rare case where no key was added to the filter
      return Slice();
    }
  } else {
    // Return the next filter partition in line and set Incomplete() status to
    // indicate we expect more calls to Finish
    *status = Status::Incomplete();
    finishing_filters = true;
    return filters.front().filter;
  }
}

PartitionedFilterBlockReader::PartitionedFilterBlockReader(
    const SliceTransform* prefix_extractor, bool _whole_key_filtering,
    BlockContents&& contents, FilterBitsReader* filter_bits_reader,
    Statistics* stats, const Comparator& comparator,
    const BlockBasedTable* table)
    : FilterBlockReader(contents.data.size(), stats, _whole_key_filtering),
      prefix_extractor_(prefix_extractor),
      comparator_(comparator),
      table_(table) {
  idx_on_fltr_blk_.reset(new Block(std::move(contents),
                                   kDisableGlobalSequenceNumber,
                                   0 /* read_amp_bytes_per_bit */, stats));
}

PartitionedFilterBlockReader::~PartitionedFilterBlockReader() {
  {
    ReadLock rl(&mu_);
    for (auto it = handle_list_.begin(); it != handle_list_.end(); ++it) {
      table_->rep_->table_options.block_cache.get()->Release(*it);
    }
  }
  char cache_key[BlockBasedTable::kMaxCacheKeyPrefixSize + kMaxVarint64Length];
  for (auto it = filter_block_set_.begin(); it != filter_block_set_.end();
       ++it) {
    auto key = BlockBasedTable::GetCacheKey(table_->rep_->cache_key_prefix,
                                            table_->rep_->cache_key_prefix_size,
                                            *it, cache_key);
    table_->rep_->table_options.block_cache.get()->Erase(key);
  }
}

bool PartitionedFilterBlockReader::KeyMayMatch(
    const Slice& key, uint64_t block_offset, const bool no_io,
    const Slice* const const_ikey_ptr) {
  assert(const_ikey_ptr != nullptr);
  assert(block_offset == kNotValid);
  if (!whole_key_filtering_) {
    return true;
  }
  if (UNLIKELY(idx_on_fltr_blk_->size() == 0)) {
    return true;
  }
  auto filter_handle = GetFilterPartitionHandle(*const_ikey_ptr);
  if (UNLIKELY(filter_handle.size() == 0)) {  // key is out of range
    return false;
  }
  bool cached = false;
  auto filter_partition = GetFilterPartition(&filter_handle, no_io, &cached);
  if (UNLIKELY(!filter_partition.value)) {
    return true;
  }
  auto res = filter_partition.value->KeyMayMatch(key, block_offset, no_io);
  if (cached) {
    return res;
  }
  if (LIKELY(filter_partition.IsSet())) {
    filter_partition.Release(table_->rep_->table_options.block_cache.get());
  } else {
    delete filter_partition.value;
  }
  return res;
}

bool PartitionedFilterBlockReader::PrefixMayMatch(
    const Slice& prefix, uint64_t block_offset, const bool no_io,
    const Slice* const const_ikey_ptr) {
  assert(const_ikey_ptr != nullptr);
  assert(block_offset == kNotValid);
  if (!prefix_extractor_) {
    return true;
  }
  if (UNLIKELY(idx_on_fltr_blk_->size() == 0)) {
    return true;
  }
  auto filter_handle = GetFilterPartitionHandle(*const_ikey_ptr);
  if (UNLIKELY(filter_handle.size() == 0)) {  // prefix is out of range
    return false;
  }
  bool cached = false;
  auto filter_partition = GetFilterPartition(&filter_handle, no_io, &cached);
  if (UNLIKELY(!filter_partition.value)) {
    return true;
  }
  auto res = filter_partition.value->PrefixMayMatch(prefix, kNotValid, no_io);
  if (cached) {
    return res;
  }
  if (LIKELY(filter_partition.IsSet())) {
    filter_partition.Release(table_->rep_->table_options.block_cache.get());
  } else {
    delete filter_partition.value;
  }
  return res;
}

Slice PartitionedFilterBlockReader::GetFilterPartitionHandle(
    const Slice& entry) {
  BlockIter iter;
  idx_on_fltr_blk_->NewIterator(&comparator_, &iter, true);
  iter.Seek(entry);
  if (UNLIKELY(!iter.Valid())) {
    return Slice();
  }
  assert(iter.Valid());
  Slice handle_value = iter.value();
  return handle_value;
}

BlockBasedTable::CachableEntry<FilterBlockReader>
PartitionedFilterBlockReader::GetFilterPartition(Slice* handle_value,
                                                 const bool no_io,
                                                 bool* cached) {
  BlockHandle fltr_blk_handle;
  auto s = fltr_blk_handle.DecodeFrom(handle_value);
  assert(s.ok());
  const bool is_a_filter_partition = true;
  auto block_cache = table_->rep_->table_options.block_cache.get();
  if (LIKELY(block_cache != nullptr)) {
    bool pin_cached_filters =
        GetLevel() == 0 &&
        table_->rep_->table_options.pin_l0_filter_and_index_blocks_in_cache;
    if (pin_cached_filters) {
      ReadLock rl(&mu_);
      auto iter = filter_cache_.find(fltr_blk_handle.offset());
      if (iter != filter_cache_.end()) {
        RecordTick(statistics(), BLOCK_CACHE_FILTER_HIT);
        *cached = true;
        return {iter->second, nullptr};
      }
    }
    auto filter =
        table_->GetFilter(fltr_blk_handle, is_a_filter_partition, no_io);
    if (filter.IsSet()) {
      WriteLock wl(&mu_);
      filter_block_set_.insert(fltr_blk_handle);
      if (pin_cached_filters) {
        std::pair<uint64_t, FilterBlockReader*> pair(fltr_blk_handle.offset(),
                                                     filter.value);
        auto succ = filter_cache_.insert(pair).second;
        if (succ) {
          handle_list_.push_back(filter.cache_handle);
        }  // Otherwise it is already inserted by a concurrent thread
        *cached = true;
      }
    }
    return filter;
  } else {
    auto filter = table_->ReadFilter(fltr_blk_handle, is_a_filter_partition);
    return {filter, nullptr};
  }
}

size_t PartitionedFilterBlockReader::ApproximateMemoryUsage() const {
  return idx_on_fltr_blk_->size();
}

}  // namespace rocksdb
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2013 Jolla Ltd.
** Contact: Petri M. Gerdt <petri.gerdt@jolla.com>
** Contact: Raine Makelainen <raine.makelainen@jolla.com>
**
****************************************************************************/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "declarativetabmodel.h"
#include "linkvalidator.h"
#include "declarativewebutils.h"

#include <QFile>
#include <QDebug>
#include <QStringList>
#include <QUrl>

#ifndef DEBUG_LOGS
#define DEBUG_LOGS 0
#endif

DeclarativeTabModel::DeclarativeTabModel(int nextTabId, QObject *parent)
    : QAbstractListModel(parent)
    , m_loaded(false)
    , m_waitingForNewTab(false)
    , m_nextTabId(nextTabId)
{
}

DeclarativeTabModel::~DeclarativeTabModel()
{
}

QHash<int, QByteArray> DeclarativeTabModel::roleNames() const
{
    QHash<int, QByteArray> roles;
    roles[ThumbPathRole] = "thumbnailPath";
    roles[TitleRole] = "title";
    roles[UrlRole] = "url";
    roles[TabIdRole] = "tabId";
    return roles;
}

void DeclarativeTabModel::addTab(const QString& url, const QString &title) {
    if (!LinkValidator::navigable(QUrl(url))) {
        return;
    }
    int tabId = createTab();
    int linkId = createLink(tabId, url, title);

    Tab tab(tabId, Link(linkId, url, "", title), 0, 0);
#if DEBUG_LOGS
    qDebug() << "new tab data:" << &tab;
#endif
    int index = m_tabs.count();
    beginInsertRows(QModelIndex(), index, index);
    m_tabs.append(tab);
    endInsertRows();
    // We should trigger this only when
    // tab is added through new window request. In all other
    // case we should keep the new tab in background.
    updateActiveTab(tab, true);

    emit countChanged();
    emit tabAdded(tabId);

    m_nextTabId = ++tabId;
    emit nextTabIdChanged();
}

int DeclarativeTabModel::nextTabId() const
{
    return m_nextTabId;
}

void DeclarativeTabModel::remove(int index) {
    if (!m_tabs.isEmpty() && index >= 0 && index < m_tabs.count()) {
        bool removingActiveTab = activeTabIndex() == index;
        removeTab(m_tabs.at(index).tabId(), m_tabs.at(index).thumbnailPath(), index);
        if (removingActiveTab) {
            if (index >= m_tabs.count()) {
                --index;
            }

            activateTab(index, false);
        }
    }
}

void DeclarativeTabModel::removeTabById(int tabId, bool activeTab)
{
    int index = -1;
    if (!activeTab) {
        index = findTabIndex(tabId);
    }

    if (activeTab) {
        closeActiveTab();
    } else if (index >= 0){
        remove(index);
    }
}

void DeclarativeTabModel::clear()
{
    if (count() == 0)
        return;

    for (int i = m_tabs.count() - 1; i >= 0; --i) {
        removeTab(m_tabs.at(i).tabId(), m_tabs.at(i).thumbnailPath(), i);
    }

    setWaitingForNewTab(true);
}

bool DeclarativeTabModel::activateTab(const QString& url)
{
    for (int i = 0; i < m_tabs.size(); i++) {
        if (m_tabs.at(i).url() == url) {
            return activateTab(i);
        }
    }
    return false;
}

bool DeclarativeTabModel::activateTab(int index, bool loadActiveTab)
{
    if (index >= 0 && index < m_tabs.count()) {
        const Tab &newActiveTab = m_tabs.at(index);
#if DEBUG_LOGS
        qDebug() << "activate tab: " << index << &newActiveTab;
#endif
        updateActiveTab(newActiveTab, loadActiveTab);
        return true;
    } else {
        return false;
    }
}

bool DeclarativeTabModel::activateTabById(int tabId)
{
    int index = findTabIndex(tabId);
    if (index >= 0) {
        return activateTab(index);
    }
    return false;
}

/**
 * @brief DeclarativeTabModel::closeActiveTab
 * Closes the active tab and activates a tab next to the current tab. If possible
 * tab that is after the current tab is activated, then falling back to previous tabs, or
 * finally none (if all closed).
 */
void DeclarativeTabModel::closeActiveTab()
{
    if (!m_tabs.isEmpty()) {
        int index = activeTabIndex();
        removeTab(m_activeTab.tabId(), m_activeTab.thumbnailPath(), index);

        if (index >= m_tabs.count()) {
            --index;
        }

        activateTab(index, true);
    }
}

void DeclarativeTabModel::newTab(const QString &url, const QString &title, int parentId)
{
    setWaitingForNewTab(true);
    emit newTabRequested(url, title, parentId);
}

void DeclarativeTabModel::dumpTabs() const
{
    for (int i = 0; i < m_tabs.size(); i++) {
        qDebug() << "tab[" << i << "]:" << &m_tabs.at(i);
    }
}

int DeclarativeTabModel::activeTabIndex() const
{
    return findTabIndex(m_activeTab.tabId());
}

int DeclarativeTabModel::count() const
{
    return m_tabs.count();
}

int DeclarativeTabModel::rowCount(const QModelIndex & parent) const {
    Q_UNUSED(parent);
    return m_tabs.count();
}

QVariant DeclarativeTabModel::data(const QModelIndex & index, int role) const {
    if (index.row() < 0 || index.row() > m_tabs.count())
        return QVariant();

    const Tab &tab = m_tabs.at(index.row());
    if (role == ThumbPathRole) {
        return tab.thumbnailPath();
    } else if (role == TitleRole) {
        return tab.title();
    } else if (role == UrlRole) {
        return tab.url();
    } else if (role == TabIdRole) {
        return tab.tabId();
    }
    return QVariant();
}

bool DeclarativeTabModel::loaded() const
{
    return m_loaded;
}

void DeclarativeTabModel::setUnloaded()
{
    if (m_loaded) {
        m_loaded = false;
        emit loadedChanged();
    }
}

bool DeclarativeTabModel::waitingForNewTab() const
{
    return m_waitingForNewTab;
}

void DeclarativeTabModel::setWaitingForNewTab(bool waiting)
{
    if (m_waitingForNewTab != waiting) {
        m_waitingForNewTab = waiting;
        emit waitingForNewTabChanged();
    }
}

const QList<Tab> &DeclarativeTabModel::tabs() const
{
    return m_tabs;
}

const Tab &DeclarativeTabModel::activeTab() const
{
    return m_activeTab;
}

bool DeclarativeTabModel::contains(int tabId) const
{
    return findTabIndex(tabId) >= 0;
}

void DeclarativeTabModel::updateUrl(int tabId, bool activeTab, QString url, bool initialLoad)
{
    updateTabUrl(tabId, activeTab, url, !initialLoad);
}

void DeclarativeTabModel::updateTitle(int tabId, bool activeTab, QString url, QString title)
{
    int tabIndex = findTabIndex(tabId);
    bool updateDb = false;
    int linkId = 0;
    if (tabIndex >= 0 && (m_tabs.at(tabIndex).title() != title || activeTab)) {
        QVector<int> roles;
        roles << TitleRole;
        m_tabs[tabIndex].setTitle(title);
        linkId = m_tabs.at(tabIndex).currentLink();
        emit dataChanged(index(tabIndex, 0), index(tabIndex, 0), roles);
        updateDb = true;

        if (tabId == m_activeTab.tabId() && activeTab) {
            m_activeTab.setTitle(title);
        }
    }

    if (updateDb) {
        updateTitle(tabId, linkId, url, title);
    }
}

void DeclarativeTabModel::removeTab(int tabId, const QString &thumbnail, int index)
{
#if DEBUG_LOGS
    qDebug() << "index:" << index << tabId;
#endif
    removeTab(tabId);
    QFile f(thumbnail);
    if (f.exists()) {
        f.remove();
    }

    if (index >= 0) {
        if (activeTabIndex() == index) {
            m_activeTab.setTabId(0);
        }
        beginRemoveRows(QModelIndex(), index, index);
        m_tabs.removeAt(index);
        endRemoveRows();
    }

    emit countChanged();
    emit tabClosed(tabId);
}

int DeclarativeTabModel::findTabIndex(int tabId) const
{
    for (int i = 0; i < m_tabs.size(); i++) {
        if (m_tabs.at(i).tabId() == tabId) {
            return i;
        }
    }
    return -1;
}

void DeclarativeTabModel::updateActiveTab(const Tab &activeTab, bool loadActiveTab)
{
#if DEBUG_LOGS
    qDebug() << "new active tab:" << &activeTab << "old active tab:" << &m_activeTab << "count:" << m_tabs.count();
#endif
    if (m_tabs.isEmpty()) {
        return;
    }

    if (m_activeTab != activeTab) {
        int oldTabId = m_activeTab.tabId();
        m_activeTab = activeTab;

        setWaitingForNewTab(true);

        // If tab has changed, update active tab role.
        int tabIndex = activeTabIndex();
        if (oldTabId != m_activeTab.tabId() && tabIndex >= 0) {
            emit activeTabIndexChanged();
        }
        // To avoid blinking we don't expose "activeTabIndex" as a model role because
        // it should be updated over here and this is too early.
        // Instead, we pass current contentItem and activeTabIndex
        // when pushing the TabPage to the PageStack. This is the signal changes the
        // contentItem of WebView.
        emit activeTabChanged(oldTabId, activeTab.tabId(), loadActiveTab);
    }
}

void DeclarativeTabModel::updateTabUrl(int tabId, bool activeTab, const QString &url, bool navigate)
{
    if (!LinkValidator::navigable(QUrl(url))) {
#if DEBUG_LOGS
        qDebug() << "invalid url: " << url;
#endif
        return;
    }

    int tabIndex = findTabIndex(tabId);
    bool updateDb = false;
    if (tabIndex >= 0 && (m_tabs.at(tabIndex).url() != url || activeTab)) {
        QVector<int> roles;
        roles << UrlRole << TitleRole << ThumbPathRole;
        m_tabs[tabIndex].setUrl(url);

        if (navigate) {
            m_tabs[tabIndex].setNextLink(0);
            int currentLinkId = m_tabs.at(tabIndex).currentLink();
            m_tabs[tabIndex].setPreviousLink(currentLinkId);
            m_tabs[tabIndex].setCurrentLink(nextLinkId());
        }
        m_tabs[tabIndex].setTitle("");
        m_tabs[tabIndex].setThumbnailPath("");

        if (tabId == m_activeTab.tabId()) {
            m_activeTab = m_tabs[tabIndex];
        }

        emit dataChanged(index(tabIndex, 0), index(tabIndex, 0), roles);
        updateDb = true;
    }

    if (updateDb) {
        if (!navigate) {
            updateTab(tabId, url, "", "");
        } else {
            navigateTo(tabId, url, "", "");
        }
    }

}

void DeclarativeTabModel::updateThumbnailPath(int tabId, QString path)
{
    if (tabId <= 0)
        return;

    QVector<int> roles;
    roles << ThumbPathRole;
    for (int i = 0; i < m_tabs.count(); i++) {
        if (m_tabs.at(i).tabId() == tabId && m_tabs.at(i).thumbnailPath() != path) {
#if DEBUG_LOGS
            qDebug() << "model tab thumbnail updated: " << path << i << tabId;
#endif
            m_tabs[i].setThumbnailPath(path);
            QModelIndex start = index(i, 0);
            QModelIndex end = index(i, 0);
            emit dataChanged(start, end, roles);
            updateThumbPath(tabId, path);
        }
    }
}
<commit_msg>[sailfish-browser] Don't update tab if not navigating<commit_after>/****************************************************************************
**
** Copyright (C) 2013 Jolla Ltd.
** Contact: Petri M. Gerdt <petri.gerdt@jolla.com>
** Contact: Raine Makelainen <raine.makelainen@jolla.com>
**
****************************************************************************/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "declarativetabmodel.h"
#include "linkvalidator.h"
#include "declarativewebutils.h"

#include <QFile>
#include <QDebug>
#include <QStringList>
#include <QUrl>

#ifndef DEBUG_LOGS
#define DEBUG_LOGS 0
#endif

DeclarativeTabModel::DeclarativeTabModel(int nextTabId, QObject *parent)
    : QAbstractListModel(parent)
    , m_loaded(false)
    , m_waitingForNewTab(false)
    , m_nextTabId(nextTabId)
{
}

DeclarativeTabModel::~DeclarativeTabModel()
{
}

QHash<int, QByteArray> DeclarativeTabModel::roleNames() const
{
    QHash<int, QByteArray> roles;
    roles[ThumbPathRole] = "thumbnailPath";
    roles[TitleRole] = "title";
    roles[UrlRole] = "url";
    roles[TabIdRole] = "tabId";
    return roles;
}

void DeclarativeTabModel::addTab(const QString& url, const QString &title) {
    if (!LinkValidator::navigable(QUrl(url))) {
        return;
    }
    int tabId = createTab();
    int linkId = createLink(tabId, url, title);

    Tab tab(tabId, Link(linkId, url, "", title), 0, 0);
#if DEBUG_LOGS
    qDebug() << "new tab data:" << &tab;
#endif
    int index = m_tabs.count();
    beginInsertRows(QModelIndex(), index, index);
    m_tabs.append(tab);
    endInsertRows();
    // We should trigger this only when
    // tab is added through new window request. In all other
    // case we should keep the new tab in background.
    updateActiveTab(tab, true);

    emit countChanged();
    emit tabAdded(tabId);

    m_nextTabId = ++tabId;
    emit nextTabIdChanged();
}

int DeclarativeTabModel::nextTabId() const
{
    return m_nextTabId;
}

void DeclarativeTabModel::remove(int index) {
    if (!m_tabs.isEmpty() && index >= 0 && index < m_tabs.count()) {
        bool removingActiveTab = activeTabIndex() == index;
        removeTab(m_tabs.at(index).tabId(), m_tabs.at(index).thumbnailPath(), index);
        if (removingActiveTab) {
            if (index >= m_tabs.count()) {
                --index;
            }

            activateTab(index, false);
        }
    }
}

void DeclarativeTabModel::removeTabById(int tabId, bool activeTab)
{
    int index = -1;
    if (!activeTab) {
        index = findTabIndex(tabId);
    }

    if (activeTab) {
        closeActiveTab();
    } else if (index >= 0){
        remove(index);
    }
}

void DeclarativeTabModel::clear()
{
    if (count() == 0)
        return;

    for (int i = m_tabs.count() - 1; i >= 0; --i) {
        removeTab(m_tabs.at(i).tabId(), m_tabs.at(i).thumbnailPath(), i);
    }

    setWaitingForNewTab(true);
}

bool DeclarativeTabModel::activateTab(const QString& url)
{
    for (int i = 0; i < m_tabs.size(); i++) {
        if (m_tabs.at(i).url() == url) {
            return activateTab(i);
        }
    }
    return false;
}

bool DeclarativeTabModel::activateTab(int index, bool loadActiveTab)
{
    if (index >= 0 && index < m_tabs.count()) {
        const Tab &newActiveTab = m_tabs.at(index);
#if DEBUG_LOGS
        qDebug() << "activate tab: " << index << &newActiveTab;
#endif
        updateActiveTab(newActiveTab, loadActiveTab);
        return true;
    } else {
        return false;
    }
}

bool DeclarativeTabModel::activateTabById(int tabId)
{
    int index = findTabIndex(tabId);
    if (index >= 0) {
        return activateTab(index);
    }
    return false;
}

/**
 * @brief DeclarativeTabModel::closeActiveTab
 * Closes the active tab and activates a tab next to the current tab. If possible
 * tab that is after the current tab is activated, then falling back to previous tabs, or
 * finally none (if all closed).
 */
void DeclarativeTabModel::closeActiveTab()
{
    if (!m_tabs.isEmpty()) {
        int index = activeTabIndex();
        removeTab(m_activeTab.tabId(), m_activeTab.thumbnailPath(), index);

        if (index >= m_tabs.count()) {
            --index;
        }

        activateTab(index, true);
    }
}

void DeclarativeTabModel::newTab(const QString &url, const QString &title, int parentId)
{
    setWaitingForNewTab(true);
    emit newTabRequested(url, title, parentId);
}

void DeclarativeTabModel::dumpTabs() const
{
    for (int i = 0; i < m_tabs.size(); i++) {
        qDebug() << "tab[" << i << "]:" << &m_tabs.at(i);
    }
}

int DeclarativeTabModel::activeTabIndex() const
{
    return findTabIndex(m_activeTab.tabId());
}

int DeclarativeTabModel::count() const
{
    return m_tabs.count();
}

int DeclarativeTabModel::rowCount(const QModelIndex & parent) const {
    Q_UNUSED(parent);
    return m_tabs.count();
}

QVariant DeclarativeTabModel::data(const QModelIndex & index, int role) const {
    if (index.row() < 0 || index.row() > m_tabs.count())
        return QVariant();

    const Tab &tab = m_tabs.at(index.row());
    if (role == ThumbPathRole) {
        return tab.thumbnailPath();
    } else if (role == TitleRole) {
        return tab.title();
    } else if (role == UrlRole) {
        return tab.url();
    } else if (role == TabIdRole) {
        return tab.tabId();
    }
    return QVariant();
}

bool DeclarativeTabModel::loaded() const
{
    return m_loaded;
}

void DeclarativeTabModel::setUnloaded()
{
    if (m_loaded) {
        m_loaded = false;
        emit loadedChanged();
    }
}

bool DeclarativeTabModel::waitingForNewTab() const
{
    return m_waitingForNewTab;
}

void DeclarativeTabModel::setWaitingForNewTab(bool waiting)
{
    if (m_waitingForNewTab != waiting) {
        m_waitingForNewTab = waiting;
        emit waitingForNewTabChanged();
    }
}

const QList<Tab> &DeclarativeTabModel::tabs() const
{
    return m_tabs;
}

const Tab &DeclarativeTabModel::activeTab() const
{
    return m_activeTab;
}

bool DeclarativeTabModel::contains(int tabId) const
{
    return findTabIndex(tabId) >= 0;
}

void DeclarativeTabModel::updateUrl(int tabId, bool activeTab, QString url, bool initialLoad)
{
    updateTabUrl(tabId, activeTab, url, !initialLoad);
}

void DeclarativeTabModel::updateTitle(int tabId, bool activeTab, QString url, QString title)
{
    int tabIndex = findTabIndex(tabId);
    bool updateDb = false;
    int linkId = 0;
    if (tabIndex >= 0 && (m_tabs.at(tabIndex).title() != title || activeTab)) {
        QVector<int> roles;
        roles << TitleRole;
        m_tabs[tabIndex].setTitle(title);
        linkId = m_tabs.at(tabIndex).currentLink();
        emit dataChanged(index(tabIndex, 0), index(tabIndex, 0), roles);
        updateDb = true;

        if (tabId == m_activeTab.tabId() && activeTab) {
            m_activeTab.setTitle(title);
        }
    }

    if (updateDb) {
        updateTitle(tabId, linkId, url, title);
    }
}

void DeclarativeTabModel::removeTab(int tabId, const QString &thumbnail, int index)
{
#if DEBUG_LOGS
    qDebug() << "index:" << index << tabId;
#endif
    removeTab(tabId);
    QFile f(thumbnail);
    if (f.exists()) {
        f.remove();
    }

    if (index >= 0) {
        if (activeTabIndex() == index) {
            m_activeTab.setTabId(0);
        }
        beginRemoveRows(QModelIndex(), index, index);
        m_tabs.removeAt(index);
        endRemoveRows();
    }

    emit countChanged();
    emit tabClosed(tabId);
}

int DeclarativeTabModel::findTabIndex(int tabId) const
{
    for (int i = 0; i < m_tabs.size(); i++) {
        if (m_tabs.at(i).tabId() == tabId) {
            return i;
        }
    }
    return -1;
}

void DeclarativeTabModel::updateActiveTab(const Tab &activeTab, bool loadActiveTab)
{
#if DEBUG_LOGS
    qDebug() << "new active tab:" << &activeTab << "old active tab:" << &m_activeTab << "count:" << m_tabs.count();
#endif
    if (m_tabs.isEmpty()) {
        return;
    }

    if (m_activeTab != activeTab) {
        int oldTabId = m_activeTab.tabId();
        m_activeTab = activeTab;

        setWaitingForNewTab(true);

        // If tab has changed, update active tab role.
        int tabIndex = activeTabIndex();
        if (oldTabId != m_activeTab.tabId() && tabIndex >= 0) {
            emit activeTabIndexChanged();
        }
        // To avoid blinking we don't expose "activeTabIndex" as a model role because
        // it should be updated over here and this is too early.
        // Instead, we pass current contentItem and activeTabIndex
        // when pushing the TabPage to the PageStack. This is the signal changes the
        // contentItem of WebView.
        emit activeTabChanged(oldTabId, activeTab.tabId(), loadActiveTab);
    }
}

void DeclarativeTabModel::updateTabUrl(int tabId, bool activeTab, const QString &url, bool navigate)
{
    if (!LinkValidator::navigable(QUrl(url))) {
#if DEBUG_LOGS
        qDebug() << "invalid url: " << url;
#endif
        return;
    }

    int tabIndex = findTabIndex(tabId);
    bool updateDb = false;
    if (tabIndex >= 0 && (m_tabs.at(tabIndex).url() != url || activeTab)) {
        QVector<int> roles;
        roles << UrlRole << TitleRole << ThumbPathRole;
        m_tabs[tabIndex].setUrl(url);

        if (navigate) {
            m_tabs[tabIndex].setNextLink(0);
            int currentLinkId = m_tabs.at(tabIndex).currentLink();
            m_tabs[tabIndex].setPreviousLink(currentLinkId);
            m_tabs[tabIndex].setCurrentLink(nextLinkId());
        }
        m_tabs[tabIndex].setTitle("");
        m_tabs[tabIndex].setThumbnailPath("");

        if (tabId == m_activeTab.tabId()) {
            m_activeTab = m_tabs[tabIndex];
        }

        emit dataChanged(index(tabIndex, 0), index(tabIndex, 0), roles);
        updateDb = true;
    }

    if (updateDb && navigate) {
        navigateTo(tabId, url, "", "");
    }

}

void DeclarativeTabModel::updateThumbnailPath(int tabId, QString path)
{
    if (tabId <= 0)
        return;

    QVector<int> roles;
    roles << ThumbPathRole;
    for (int i = 0; i < m_tabs.count(); i++) {
        if (m_tabs.at(i).tabId() == tabId && m_tabs.at(i).thumbnailPath() != path) {
#if DEBUG_LOGS
            qDebug() << "model tab thumbnail updated: " << path << i << tabId;
#endif
            m_tabs[i].setThumbnailPath(path);
            QModelIndex start = index(i, 0);
            QModelIndex end = index(i, 0);
            emit dataChanged(start, end, roles);
            updateThumbPath(tabId, path);
        }
    }
}
<|endoftext|>


<commit_before>#include "decoder.h"

string decode_png_buffer(char * buffer, size_t size, CImg<unsigned char> ** cimg, char ** metadata) {

    // check it's a valid png buffer
    if (size < 8 || png_sig_cmp((png_const_bytep) buffer, 0, 8)) {
        return "Invalid PNG buffer";
    }

    png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
                          NULL, NULL, NULL);
    if (!png_ptr) {
        return "Out of memory";
    }

    png_infop info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr) {
        png_destroy_read_struct(&png_ptr, NULL, NULL);
        return "Out of memory";
    }

    png_infop end_info = png_create_info_struct(png_ptr);
    if (!end_info) {
        png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
        return "Out of memory";
    }

    // Error handling callback for png file reading
    if (setjmp(png_jmpbuf(png_ptr))) {
        png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
        return "PNG decoding error";
    }

    pngReadCbData buffinf = {(unsigned char *) buffer, size, 0};
    png_set_read_fn(png_ptr, (voidp) &buffinf, pngReadCB);

    // PNG info
    png_read_info(png_ptr, info_ptr);
    png_set_sig_bytes(png_ptr, 8);

    png_uint_32 width = 0, height = 0;
    int bit_depth, color_type;
    bool is_gray = false;
    png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
                 NULL, NULL, NULL);

    // get metadata in first text chunk found with keyboard 'lwip_data'
    png_textp text_ptr;
    int num_comments = png_get_text(png_ptr, info_ptr, &text_ptr, NULL);
    bool metadata_found = false;

    for (int i = 0; i < num_comments; i++) {
        if (strcmp(text_ptr[i].key, "lwip_data") == 0) {
            int metadata_len = (strlen(text_ptr[i].text) + 1) * sizeof(char);
            *metadata = (char *)malloc(metadata_len);
            memcpy(*metadata, text_ptr[i].text, metadata_len);
            break; //TODO: handle multiple lwip_data text chunks?
        }
    }

    if (color_type == PNG_COLOR_TYPE_PALETTE) {
        png_set_palette_to_rgb(png_ptr);
        color_type = PNG_COLOR_TYPE_RGB;
        bit_depth = 8;
    }
    if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) {
        png_set_expand_gray_1_2_4_to_8(png_ptr);
        is_gray = true;
        bit_depth = 8;
    }
    if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
        png_set_tRNS_to_alpha(png_ptr);
        color_type |= PNG_COLOR_MASK_ALPHA;
    }
    if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
        png_set_gray_to_rgb(png_ptr);
        color_type |= PNG_COLOR_MASK_COLOR;
        is_gray = true;
    }
    if (color_type == PNG_COLOR_TYPE_RGB)
        png_set_filler(png_ptr, 0xffffU, PNG_FILLER_AFTER);

    if (!(color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_RGB_ALPHA)) {
        png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
        return "Invalid PNG color coding";
    }

    if (bit_depth != 8 && bit_depth != 16) {
        png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
        return "Invalid PNG bit depth";
    }

    bool is_alpha = (color_type == PNG_COLOR_TYPE_RGBA);

    png_read_update_info(png_ptr, info_ptr);
    const int byte_depth = bit_depth >> 3;

    // Allocate Memory for Image Read
    png_bytep * const imgData = new png_bytep[height];
    for (unsigned int row = 0; row < height; ++row)
        imgData[row] = new png_byte[byte_depth * N_CHANNELS * width];
    png_read_image(png_ptr, imgData);
    png_read_end(png_ptr, end_info);

    *cimg = new CImg<unsigned char>();
    (*cimg)->assign(width, height, 1, (is_gray ? 1 : 3) + (is_alpha ? 1 : 0));
    unsigned char * ptr_r = (*cimg)->data(0, 0, 0, 0),
                    *ptr_g = is_gray ? 0 : (*cimg)->data(0, 0, 0, 1),
                     *ptr_b = is_gray ? 0 : (*cimg)->data(0, 0, 0, 2),
                      *ptr_a = is_alpha ? (*cimg)->data(0, 0, 0, is_gray ? 1 : 3) : NULL;
    switch (bit_depth) {
    case 8:
        cimg_forY(**cimg, y) {
            const unsigned char * ptrs = (unsigned char *)imgData[y];
            cimg_forX(**cimg, x) {
                *(ptr_r++) = (unsigned char) * (ptrs++);
                if (ptr_g) *(ptr_g++) = (unsigned char) * (ptrs++); else ++ptrs;
                if (ptr_b) *(ptr_b++) = (unsigned char) * (ptrs++); else ++ptrs;
                if (ptr_a) *(ptr_a++) = (unsigned char) * (ptrs++); else ++ptrs;
            }
        }
        break;
    case 16:
        cimg_forY(**cimg, y) {
            const unsigned short * ptrs = (unsigned short *)(imgData[y]);
            if (!cimg::endianness()) cimg::invert_endianness(ptrs, N_CHANNELS * (*cimg)->width());
            cimg_forX(**cimg, x) {
                *(ptr_r++) = (unsigned char) * (ptrs++);
                if (ptr_g) *(ptr_g++) = (unsigned char) * (ptrs++); else ++ptrs;
                if (ptr_b) *(ptr_b++) = (unsigned char) * (ptrs++); else ++ptrs;
                if (ptr_a) *(ptr_a++) = (unsigned char) * (ptrs++); else ++ptrs;
            }
        }
        break;
    }

    png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);

    // Deallocate Image Read Memory
    cimg_forY(**cimg, n) delete[] imgData[n];
    delete[] imgData;

    return "";
}

void pngReadCB(png_structp png_ptr, png_bytep data, png_size_t length) {
    pngReadCbData * buffinf = (pngReadCbData *) png_get_io_ptr(png_ptr);

    // need to read 'length' bytes from the source buffer and copy them to data.
    if (buffinf->read + length > buffinf->size) {
        // no more bytes in source
        png_error(png_ptr, "PNG source buffer is missing data");
        return;
    }

    memcpy(data, buffinf->src + buffinf->read, length);
    buffinf->read += length;

    return;
}
<commit_msg>Remove unnecessary variable.<commit_after>#include "decoder.h"

string decode_png_buffer(char * buffer, size_t size, CImg<unsigned char> ** cimg, char ** metadata) {

    // check it's a valid png buffer
    if (size < 8 || png_sig_cmp((png_const_bytep) buffer, 0, 8)) {
        return "Invalid PNG buffer";
    }

    png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
                          NULL, NULL, NULL);
    if (!png_ptr) {
        return "Out of memory";
    }

    png_infop info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr) {
        png_destroy_read_struct(&png_ptr, NULL, NULL);
        return "Out of memory";
    }

    png_infop end_info = png_create_info_struct(png_ptr);
    if (!end_info) {
        png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
        return "Out of memory";
    }

    // Error handling callback for png file reading
    if (setjmp(png_jmpbuf(png_ptr))) {
        png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
        return "PNG decoding error";
    }

    pngReadCbData buffinf = {(unsigned char *) buffer, size, 0};
    png_set_read_fn(png_ptr, (voidp) &buffinf, pngReadCB);

    // PNG info
    png_read_info(png_ptr, info_ptr);
    png_set_sig_bytes(png_ptr, 8);

    png_uint_32 width = 0, height = 0;
    int bit_depth, color_type;
    bool is_gray = false;
    png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
                 NULL, NULL, NULL);

    // get metadata in first text chunk found with keyboard 'lwip_data'
    png_textp text_ptr;
    int num_comments = png_get_text(png_ptr, info_ptr, &text_ptr, NULL);

    for (int i = 0; i < num_comments; i++) {
        if (strcmp(text_ptr[i].key, "lwip_data") == 0) {
            int metadata_len = (strlen(text_ptr[i].text) + 1) * sizeof(char);
            *metadata = (char *)malloc(metadata_len);
            memcpy(*metadata, text_ptr[i].text, metadata_len);
            break; //TODO: handle multiple lwip_data text chunks?
        }
    }

    if (color_type == PNG_COLOR_TYPE_PALETTE) {
        png_set_palette_to_rgb(png_ptr);
        color_type = PNG_COLOR_TYPE_RGB;
        bit_depth = 8;
    }
    if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) {
        png_set_expand_gray_1_2_4_to_8(png_ptr);
        is_gray = true;
        bit_depth = 8;
    }
    if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
        png_set_tRNS_to_alpha(png_ptr);
        color_type |= PNG_COLOR_MASK_ALPHA;
    }
    if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
        png_set_gray_to_rgb(png_ptr);
        color_type |= PNG_COLOR_MASK_COLOR;
        is_gray = true;
    }
    if (color_type == PNG_COLOR_TYPE_RGB)
        png_set_filler(png_ptr, 0xffffU, PNG_FILLER_AFTER);

    if (!(color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_RGB_ALPHA)) {
        png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
        return "Invalid PNG color coding";
    }

    if (bit_depth != 8 && bit_depth != 16) {
        png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
        return "Invalid PNG bit depth";
    }

    bool is_alpha = (color_type == PNG_COLOR_TYPE_RGBA);

    png_read_update_info(png_ptr, info_ptr);
    const int byte_depth = bit_depth >> 3;

    // Allocate Memory for Image Read
    png_bytep * const imgData = new png_bytep[height];
    for (unsigned int row = 0; row < height; ++row)
        imgData[row] = new png_byte[byte_depth * N_CHANNELS * width];
    png_read_image(png_ptr, imgData);
    png_read_end(png_ptr, end_info);

    *cimg = new CImg<unsigned char>();
    (*cimg)->assign(width, height, 1, (is_gray ? 1 : 3) + (is_alpha ? 1 : 0));
    unsigned char * ptr_r = (*cimg)->data(0, 0, 0, 0),
                    *ptr_g = is_gray ? 0 : (*cimg)->data(0, 0, 0, 1),
                     *ptr_b = is_gray ? 0 : (*cimg)->data(0, 0, 0, 2),
                      *ptr_a = is_alpha ? (*cimg)->data(0, 0, 0, is_gray ? 1 : 3) : NULL;
    switch (bit_depth) {
    case 8:
        cimg_forY(**cimg, y) {
            const unsigned char * ptrs = (unsigned char *)imgData[y];
            cimg_forX(**cimg, x) {
                *(ptr_r++) = (unsigned char) * (ptrs++);
                if (ptr_g) *(ptr_g++) = (unsigned char) * (ptrs++); else ++ptrs;
                if (ptr_b) *(ptr_b++) = (unsigned char) * (ptrs++); else ++ptrs;
                if (ptr_a) *(ptr_a++) = (unsigned char) * (ptrs++); else ++ptrs;
            }
        }
        break;
    case 16:
        cimg_forY(**cimg, y) {
            const unsigned short * ptrs = (unsigned short *)(imgData[y]);
            if (!cimg::endianness()) cimg::invert_endianness(ptrs, N_CHANNELS * (*cimg)->width());
            cimg_forX(**cimg, x) {
                *(ptr_r++) = (unsigned char) * (ptrs++);
                if (ptr_g) *(ptr_g++) = (unsigned char) * (ptrs++); else ++ptrs;
                if (ptr_b) *(ptr_b++) = (unsigned char) * (ptrs++); else ++ptrs;
                if (ptr_a) *(ptr_a++) = (unsigned char) * (ptrs++); else ++ptrs;
            }
        }
        break;
    }

    png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);

    // Deallocate Image Read Memory
    cimg_forY(**cimg, n) delete[] imgData[n];
    delete[] imgData;

    return "";
}

void pngReadCB(png_structp png_ptr, png_bytep data, png_size_t length) {
    pngReadCbData * buffinf = (pngReadCbData *) png_get_io_ptr(png_ptr);

    // need to read 'length' bytes from the source buffer and copy them to data.
    if (buffinf->read + length > buffinf->size) {
        // no more bytes in source
        png_error(png_ptr, "PNG source buffer is missing data");
        return;
    }

    memcpy(data, buffinf->src + buffinf->read, length);
    buffinf->read += length;

    return;
}
<|endoftext|>


<commit_before>/**
 * @file Cosa/Canvas/Driver/ILI9163.hh
 * @version 1.0
 *
 * @section License
 * Copyright (C) 2015, Mikael Patel
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * This file is part of the Arduino Che Cosa project.
 */

#ifndef COSA_CANVAS_DRIVER_ILI9163_HH
#define COSA_CANVAS_DRIVER_ILI9163_HH

#include "Cosa/Canvas/Driver/GDDRAM.hh"

/**
 * Device driver for ILI9163, TFT LCD Single Chip Driver,
 * 240x320 Resolution and max 262K color. The device driver uses
 * 16-bit color. See Canvas and GDDRAM abstract driver.
 *
 * @section Circuit
 * Please note that 3V3 level signals are required. The reset signal
 * is optional.
 *
 * @code
 *                           ILI9163
 *                       +------------+
 * (VCC)---------------1-|VCC         |
 * (GND)---------------2-|GND         |
 * (SS/D10)------------3-|CS          |
 * (RST*)--------------4-|RST         |
 * (D9)----------------5-|DC          |
 * (MOSI/D11)----------6-|SDI         |
 * (SCK/D13)-----------7-|SCK         |
 * (VCC)------[330]----8-|LED         |
 * (MISO/D12)----------9-|SDO         |
 *                       +------------+
 * @endcode
 *
 * @section References
 * 1. ILITEK. ILI9163 specification, V0.18.
 *
 * @section Acknowledgements
 * Inspired by graphics library by ladyada/adafruit.
 *
 */
class ILI9163 : public GDDRAM {
public:
  /**
   * Construct ILI9163 canvas object with given control pins.
   * @param[in] cs slave selection pin (default pin 10).
   * @param[in] dc data/command selection pin (default pin 9).
   */
#if defined(BOARD_ATTINYX4)
  ILI9163(Board::DigitalPin cs = Board::D3,
	  Board::DigitalPin dc = Board::D7);
#elif defined(BOARD_ATTINYX5)
  ILI9163(Board::DigitalPin cs = Board::D3,
	  Board::DigitalPin dc = Board::D4);
#else
  ILI9163(Board::DigitalPin cs = Board::D10,
	  Board::DigitalPin dc = Board::D9);
#endif

  /**
   * Screen size (width and height).
   */
  static const uint16_t SCREEN_WIDTH = 128;
  static const uint16_t SCREEN_HEIGHT = 128;

  /**
   * @override Canvas
   * Set screen orientation.
   * @param[in] direction.
   */
  virtual uint8_t set_orientation(uint8_t direction);

protected:
  /**
   * @override GDDRAM
   * Get initialization script (in program memory).
   * @return pointer to script.
   */
  virtual const uint8_t* get_script()
  {
    return (script);
  }

  /**
   * Initialization script (in program memory).
   */
  static const uint8_t script[] PROGMEM;
};
#endif
<commit_msg>Update documentation.<commit_after>/**
 * @file Cosa/Canvas/Driver/ILI9163.hh
 * @version 1.0
 *
 * @section License
 * Copyright (C) 2015, Mikael Patel
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * This file is part of the Arduino Che Cosa project.
 */

#ifndef COSA_CANVAS_DRIVER_ILI9163_HH
#define COSA_CANVAS_DRIVER_ILI9163_HH

#include "Cosa/Canvas/Driver/GDDRAM.hh"

/**
 * Device driver for ILI9163, TFT LCD Single Chip Driver,
 * 128x128 Resolution and max 262K color. The device driver uses
 * 16-bit color. See Canvas and GDDRAM abstract driver.
 *
 * @section Circuit
 * Please note that 3V3 level signals are required. The reset signal
 * is optional.
 *
 * @code
 *                           ILI9163
 *                       +------------+
 * (VCC)---------------1-|VCC         |
 * (GND)---------------2-|GND         |
 * (SS/D10)------------3-|CS          |
 * (RST*)--------------4-|RST         |
 * (D9)----------------5-|DC          |
 * (MOSI/D11)----------6-|SDI         |
 * (SCK/D13)-----------7-|SCK         |
 * (VCC)------[330]----8-|LED         |
 *                       +------------+
 * @endcode
 *
 * @section References
 * 1. ILITEK. ILI9163 specification, V0.18.
 *
 * @section Acknowledgements
 * Inspired by graphics library by ladyada/adafruit.
 *
 */
class ILI9163 : public GDDRAM {
public:
  /**
   * Construct ILI9163 canvas object with given control pins.
   * @param[in] cs slave selection pin (default pin 10).
   * @param[in] dc data/command selection pin (default pin 9).
   */
#if defined(BOARD_ATTINYX4)
  ILI9163(Board::DigitalPin cs = Board::D3,
	  Board::DigitalPin dc = Board::D7);
#elif defined(BOARD_ATTINYX5)
  ILI9163(Board::DigitalPin cs = Board::D3,
	  Board::DigitalPin dc = Board::D4);
#else
  ILI9163(Board::DigitalPin cs = Board::D10,
	  Board::DigitalPin dc = Board::D9);
#endif

  /**
   * Screen size (width and height).
   */
  static const uint16_t SCREEN_WIDTH = 128;
  static const uint16_t SCREEN_HEIGHT = 128;

  /**
   * @override Canvas
   * Set screen orientation.
   * @param[in] direction.
   */
  virtual uint8_t set_orientation(uint8_t direction);

protected:
  /**
   * @override GDDRAM
   * Get initialization script (in program memory).
   * @return pointer to script.
   */
  virtual const uint8_t* get_script()
  {
    return (script);
  }

  /**
   * Initialization script (in program memory).
   */
  static const uint8_t script[] PROGMEM;
};
#endif
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2006 Apple Computer, Inc.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 "config.h"
#include "ChromiumBridge.h"
#include "CString.h"
#include "MIMETypeRegistry.h"
#include "MediaPlayer.h"
#include "StringHash.h"
#include <wtf/HashMap.h>
#include <wtf/HashSet.h>

namespace WebCore
{

// NOTE: the following methods are unimplemented
// (and will give linker error if used):
//   HashSet<String> &MIMETypeRegistry::getSupportedImageMIMETypes()
//   HashSet<String> &MIMETypeRegistry::getSupportedImageResourceMIMETypes()
// These methods are referenced by WebKit but not WebCore.
// Therefore defering their implementation until necessary.
// Since the returned HashSet is mutable, chrome would need to synchronize
// the mime type registry between renderer/browser. This one is called, but we
// currently stub it out until this can be resolved.
HashSet<String>& MIMETypeRegistry::getSupportedNonImageMIMETypes()
{
    static HashSet<String> supportedNonImageMIMETypes;
    return supportedNonImageMIMETypes;
}

// Checks if any of the plugins handle this extension, and if so returns the
// plugin's mime type for this extension.  Otherwise returns an empty string.
String GetPluginMimeTypeFromExtension(const String& extension);

String MIMETypeRegistry::getMIMETypeForPath(const String& path)
{
    int pos = path.reverseFind('.');
    if (pos < 0)
        return "application/octet-stream";
    String extension = path.substring(pos + 1);
    String mimeType = getMIMETypeForExtension(extension);
    if (mimeType.isEmpty()) {
        // If there's no mimetype registered for the extension, check to see
        // if a plugin can handle the extension.
        mimeType = GetPluginMimeTypeFromExtension(extension);
    }
    return mimeType;
}

bool MIMETypeRegistry::isSupportedImageMIMEType(const String& mimeType)
{
    return !mimeType.isEmpty()
        && ChromiumBridge::isSupportedImageMIMEType(mimeType.latin1().data());
}

bool MIMETypeRegistry::isSupportedImageMIMETypeForEncoding(const String& mimeType)
{
    // TODO(brettw) fill this out. See: http://trac.webkit.org/changeset/30888
    return isSupportedImageMIMEType(mimeType);
}

bool MIMETypeRegistry::isSupportedJavaScriptMIMEType(const String& mimeType)
{
    const char* data = mimeType.latin1().data();
    return !mimeType.isEmpty()
        && ChromiumBridge::isSupportedJavascriptMIMEType(data);
}

bool MIMETypeRegistry::isSupportedImageResourceMIMEType(const String& mimeType)
{
    return isSupportedImageMIMEType(mimeType);
}

bool MIMETypeRegistry::isSupportedNonImageMIMEType(const String& mimeType)
{
   return !mimeType.isEmpty()
       && ChromiumBridge::isSupportedNonImageMIMEType(mimeType.latin1().data());
}

#if ENABLE(VIDEO)
bool MIMETypeRegistry::isSupportedMediaMIMEType(const String& mimeType)
{
    return MediaPlayer::supportsType(mimeType);
}
#endif

bool MIMETypeRegistry::isJavaAppletMIMEType(const String& mimeType)
{
    // Since this set is very limited and is likely to remain so we won't bother with the overhead
    // of using a hash set.
    // Any of the MIME types below may be followed by any number of specific versions of the JVM,
    // which is why we use startsWith()
    return mimeType.startsWith("application/x-java-applet", false)
        || mimeType.startsWith("application/x-java-bean", false)
        || mimeType.startsWith("application/x-java-vm", false);
}

}  // namespace WebCore
<commit_msg>Fix test failures caused by bad temporary variable.<commit_after>/*
 * Copyright (C) 2006 Apple Computer, Inc.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 "config.h"
#include "ChromiumBridge.h"
#include "CString.h"
#include "MIMETypeRegistry.h"
#include "MediaPlayer.h"
#include "StringHash.h"
#include <wtf/HashMap.h>
#include <wtf/HashSet.h>

namespace WebCore
{

// NOTE: the following methods are unimplemented
// (and will give linker error if used):
//   HashSet<String> &MIMETypeRegistry::getSupportedImageMIMETypes()
//   HashSet<String> &MIMETypeRegistry::getSupportedImageResourceMIMETypes()
// These methods are referenced by WebKit but not WebCore.
// Therefore defering their implementation until necessary.
// Since the returned HashSet is mutable, chrome would need to synchronize
// the mime type registry between renderer/browser. This one is called, but we
// currently stub it out until this can be resolved.
HashSet<String>& MIMETypeRegistry::getSupportedNonImageMIMETypes()
{
    static HashSet<String> supportedNonImageMIMETypes;
    return supportedNonImageMIMETypes;
}

// Checks if any of the plugins handle this extension, and if so returns the
// plugin's mime type for this extension.  Otherwise returns an empty string.
String GetPluginMimeTypeFromExtension(const String& extension);

String MIMETypeRegistry::getMIMETypeForPath(const String& path)
{
    int pos = path.reverseFind('.');
    if (pos < 0)
        return "application/octet-stream";
    String extension = path.substring(pos + 1);
    String mimeType = getMIMETypeForExtension(extension);
    if (mimeType.isEmpty()) {
        // If there's no mimetype registered for the extension, check to see
        // if a plugin can handle the extension.
        mimeType = GetPluginMimeTypeFromExtension(extension);
    }
    return mimeType;
}

bool MIMETypeRegistry::isSupportedImageMIMEType(const String& mimeType)
{
    return !mimeType.isEmpty()
        && ChromiumBridge::isSupportedImageMIMEType(mimeType.latin1().data());
}

bool MIMETypeRegistry::isSupportedImageMIMETypeForEncoding(const String& mimeType)
{
    // TODO(brettw) fill this out. See: http://trac.webkit.org/changeset/30888
    return isSupportedImageMIMEType(mimeType);
}

bool MIMETypeRegistry::isSupportedJavaScriptMIMEType(const String& mimeType)
{
    return !mimeType.isEmpty()
        && ChromiumBridge::isSupportedJavascriptMIMEType(mimeType.latin1().data());
}

bool MIMETypeRegistry::isSupportedImageResourceMIMEType(const String& mimeType)
{
    return isSupportedImageMIMEType(mimeType);
}

bool MIMETypeRegistry::isSupportedNonImageMIMEType(const String& mimeType)
{
   return !mimeType.isEmpty()
       && ChromiumBridge::isSupportedNonImageMIMEType(mimeType.latin1().data());
}

#if ENABLE(VIDEO)
bool MIMETypeRegistry::isSupportedMediaMIMEType(const String& mimeType)
{
    return MediaPlayer::supportsType(mimeType);
}
#endif

bool MIMETypeRegistry::isJavaAppletMIMEType(const String& mimeType)
{
    // Since this set is very limited and is likely to remain so we won't bother with the overhead
    // of using a hash set.
    // Any of the MIME types below may be followed by any number of specific versions of the JVM,
    // which is why we use startsWith()
    return mimeType.startsWith("application/x-java-applet", false)
        || mimeType.startsWith("application/x-java-bean", false)
        || mimeType.startsWith("application/x-java-vm", false);
}

}  // namespace WebCore
<|endoftext|>