<commit_before>//debugging level 0 = nothing
//debugging level 1 = critical errors
//debugging level 2 = errors
//debugging level 3 = status information
//debugging level 4 = extremely verbose status information
#define DEBUG 3

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/epoll.h>
#include <getopt.h>

enum {HANDLER_PROGRESSIVE, HANDLER_FLASH, HANDLER_APPLE, HANDLER_MICRO};

#define DEFAULT_PORT 80
#include "../util/server_setup.cpp"
#include "../util/http_parser.cpp"
#include "../MP4/interface.h"

int FlvToFragNum( FLV_Pack * tag ) {
  int Timestamp = (tag->data[7] << 24 ) + (tag->data[4] << 16 ) + (tag->data[5] << 8 ) + (tag->data[6] );
  return (Timestamp / 10000) + 1;
}

std::string BuildManifest( std::string MetaData, std::string MovieId, int CurrentMediaTime ) {
  Interface * temp = new Interface;
  std::string Result="<manifest>\n";
  Result += "  <mimeType>video/mp4</mimeType>\n";
  Result += "  <streamType>live</streamType>\n";
  Result += "  <deliveryType>streaming</deliveryType>\n";
  Result += "  <bootstrapInfo profile=\"named\" id=\"bootstrap1\">\n";
  //JARON: Encode BASE64
  Result += temp->GenerateLiveBootstrap( CurrentMediaTime );
  Result += "  </bootstrapInfo>\n";
  Result += "  <media streamId=\"1\" bootstrapInfoId=\"bootstrap1\" url=\"";
  Result += MovieId;
  Result += "/\">";
  Result += "    <metadata>\n";
  //JARON: Encode BASE64
  Result += MetaData;
  Result += "    </metadata>\n";
  Result += "  </media>\n";
  Result += "</manifest>\n";
  delete temp;
  return Result;
}

int mainHandler(int CONN_fd){
  int handler = HANDLER_PROGRESSIVE;
  bool ready4data = false;//set to true when streaming starts
  bool inited = false;
  bool progressive_has_sent_header = false;
  int ss;
  std::string streamname;
  std::string FlashBuf;
  std::string FlashMeta;
  bool Flash_ManifestSent = false;
  FLV_Pack * tag = 0;
  HTTPReader HTTP_R, HTTP_S;//HTTP Receiver en HTTP Sender.

  int retval;
  int poller = epoll_create(1);
  int sspoller = epoll_create(1);
  struct epoll_event ev;
  ev.events = EPOLLIN;
  ev.data.fd = CONN_fd;
  epoll_ctl(poller, EPOLL_CTL_ADD, CONN_fd, &ev);
  struct epoll_event events[1];

  std::string Movie = "";
  std::string Quality = "";
  int Segment = -1;
  int ReqFragment = -1;
  int temp;
  int CurrentFragment = -1;

  while (!socketError && !All_Hell_Broke_Loose){
    //only parse input if available or not yet init'ed
    retval = epoll_wait(poller, events, 1, 1);
    if ((retval > 0) || !ready4data){
      if (HTTP_R.ReadSocket(CONN_fd)){
        if( (HTTP_R.url.find("Seg") != std::string::npos) &&
            (HTTP_R.url.find("Frag") != std::string::npos) ) {
          handler = HANDLER_FLASH;
        }
        printf( "Handler: %d\n", handler );
        if(handler == HANDLER_FLASH) {
          Movie = HTTP_R.url.substr(1);
          Movie = Movie.substr(0,Movie.find("/"));
          Quality = HTTP_R.url.substr( HTTP_R.url.find("/",1)+1 );
          Quality = Quality.substr(0, Quality.find("Seg"));
          temp = HTTP_R.url.find("Seg") + 3;
          Segment = atoi( HTTP_R.url.substr(temp,HTTP_R.url.find("-",temp)-temp).c_str());
          temp = HTTP_R.url.find("Frag") + 4;
          ReqFragment = atoi( HTTP_R.url.substr(temp).c_str() );

          printf( "URL: %s\n", HTTP_R.url.c_str());
          printf( "Movie Identifier: %s\n", Movie.c_str() );
          printf( "Quality Modifier: %s\n", Quality.c_str() );
          printf( "Segment: %d\n", Segment );
          printf( "Fragment: %d\n", ReqFragment );
          streamname = "/tmp/shared_socket_";
          for (std::string::iterator i=Movie.end()-1; i>=Movie.begin(); --i){
            if (!isalpha(*i) && !isdigit(*i)){
              Movie.erase(i);
            }else{
              *i=tolower(*i);
            }//strip nonalphanumeric
          }
          streamname += Movie;

          ready4data = true;
        }//FLASH handler
        //ERIK: we hebben nu een hele HTTP request geparsed - verwerken mag hier, door aanroepen naar
        //ERIK: bijvoorbeeld HTTP_R.GetHeader("headernaam") (voor headers) of HTTP_R.GetVar("varnaam") (voor GET/POST vars)
        //ERIK: of HTTP_R.method of HTTP_R.url of HTTP_R.protocol....
        //ERIK: zie ook ../util/http_parser.cpp - de class definitie bovenaan zou genoeg moeten zijn voor je

        //ERIK: Ik heb een handler variabele gemaakt die moet setten naar bijv HANDLER_FLASH in jouw geval.
        //ERIK: Als de handler niet is geset, is hij by default PROGRESSIVE, en daarvoor heb ik de verwerking al gecode.
        //ERIK: Je eigen handler instellen voorkomt dus dat mijn code hem handled alsof hij progressive is.
        if (handler == HANDLER_PROGRESSIVE){
          //in het geval progressive nemen we aan dat de URL de streamname is, met .flv erachter
          streamname = HTTP_R.url.substr(0, HTTP_R.url.size()-4);//strip de .flv
          for (std::string::iterator i=streamname.end()-1; i>=streamname.begin(); --i){
            if (!isalpha(*i) && !isdigit(*i)){streamname.erase(i);}else{*i=tolower(*i);}//strip nonalphanumeric
          }
          streamname = "/tmp/shared_socket_" + streamname;//dit is dan onze shared_socket
          //normaal zouden we ook een position uitlezen uit de URL, maar bij LIVE streams is dat zinloos
  printf( "Streamname: %s\n", streamname.c_str() );
          ready4data = true;
        }//PROGRESSIVE handler
        HTTP_R.Clean(); //maak schoon na verwerken voor eventuele volgende requests...
      }
    }
    if (ready4data){
      if (!inited){
        //we are ready, connect the socket!
        ss = DDV_OpenUnix(streamname);
        if (ss <= 0){
          #if DEBUG >= 1
          fprintf(stderr, "Could not connect to server!\n");
          #endif
          socketError = 1;
          break;
        }
        ev.events = EPOLLIN;
        ev.data.fd = ss;
        epoll_ctl(sspoller, EPOLL_CTL_ADD, ss, &ev);
        #if DEBUG >= 3
        fprintf(stderr, "Everything connected, starting to send video data...\n");
        #endif
        inited = true;
      }
      retval = epoll_wait(sspoller, events, 1, 1);
      switch (DDV_ready(ss)){
        case 0:
          socketError = true;
          #if DEBUG >= 1
          fprintf(stderr, "Source socket is disconnected.\n");
          #endif
          break;
        case -1: break;//not ready yet
        default:
          if (FLV_GetPacket(tag, ss)){//able to read a full packet?
            //ERIK: "tag" bevat nu een FLV tag (video, audio, of metadata), de header hebben we al weggelezen, np.
            //ERIK: Dit is het punt waarop je eventueel data mag/kan gaan sturen en/of parsen. Leef je uit.
            //ERIK: je kan een HTTP_S gebruiken om je HTTP request op te bouwen (via SetBody, SetHeader, etc)
            //ERIK: en dan met de .BuildResponse("200", "OK"); call een std::string met de hele response maken, klaar voor versturen
            //ERIK: Note: hergebruik echter NIET de HTTP_R die ik al heb gemaakt hierboven, want er kunnen meerdere requests binnenkomen!
            if (handler == HANDLER_FLASH){
              if(tag->data[0] != 0x12 ) {
                FlashBuf.append(tag->data,tag->len);
              } else {
                FlashMeta = "";
                FlashMeta.append(tag->data,tag->len);
                if( !Flash_ManifestSent ) {
                  HTTP_S.Clean();
                  HTTP_S.SetHeader("Content-Type","text/xml");
                  HTTP_S.SetHeader("Cache-Control","no-cache");
//                  HTTP_S.SetBody
                }
              }
            }
            if (handler == HANDLER_PROGRESSIVE){
              if (!progressive_has_sent_header){
                HTTP_S.Clean();//troep opruimen die misschien aanwezig is...
                HTTP_S.SetHeader("Content-Type", "video/x-flv");//FLV files hebben altijd dit content-type.
                std::string tmpresp = HTTP_S.BuildResponse("200", "OK");//geen SetBody = unknown length! Dat willen we hier.
                DDV_write(tmpresp.c_str(), tmpresp.size(), CONN_fd);//schrijf de HTTP response header
                DDV_write(FLVHeader, 13, CONN_fd);//schrijf de FLV header, altijd 13 chars lang
                progressive_has_sent_header = true;
              }
              DDV_write(tag->data, tag->len, CONN_fd);//schrijf deze FLV tag onbewerkt weg
            }//PROGRESSIVE handler
          }
          break;
      }
    }
  }
  close(CONN_fd);
  if (inited) close(ss);
  #if DEBUG >= 1
  if (All_Hell_Broke_Loose){fprintf(stderr, "All Hell Broke Loose\n");}
  fprintf(stderr, "User %i disconnected.\n", CONN_fd);
  if (inited){
    fprintf(stderr, "Status was: inited\n");
  }else{
    if (ready4data){
      fprintf(stderr, "Status was: ready4data\n");
    }else{
      fprintf(stderr, "Status was: connected\n");
    }
  }
  #endif
  return 0;
}

<commit_msg>Base64 encoding en zo<commit_after>//debugging level 0 = nothing
//debugging level 1 = critical errors
//debugging level 2 = errors
//debugging level 3 = status information
//debugging level 4 = extremely verbose status information
#define DEBUG 4

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/epoll.h>
#include <getopt.h>

enum {HANDLER_NONE, HANDLER_PROGRESSIVE, HANDLER_FLASH, HANDLER_APPLE, HANDLER_MICRO};

#define DEFAULT_PORT 80
#include "../util/server_setup.cpp"
#include "../util/http_parser.cpp"
#include "../MP4/interface.h"

static const std::string base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
std::string base64_encode(std::string const input) {
  std::string ret;
  unsigned int in_len = input.size();
  char quad[4], triple[3];
  int i, x, n = 3;
  for (x = 0; x < in_len; x = x + 3){
    if ((in_len - x) / 3 == 0){n = (in_len - x) % 3;}
    for (i=0; i < 3; i++){triple[i] = '0';}
    for (i=0; i < n; i++){triple[i] = input[x + i];}
    quad[0] = base64_chars[(triple[0] & 0xFC) >> 2]; // FC = 11111100
    quad[1] = base64_chars[((triple[0] & 0x03) << 4) | ((triple[1] & 0xF0) >> 4)]; // 03 = 11
    quad[2] = base64_chars[((triple[1] & 0x0F) << 2) | ((triple[2] & 0xC0) >> 6)]; // 0F = 1111, C0=11110
    quad[3] = base64_chars[triple[2] & 0x3F]; // 3F = 111111
    if (n < 3){quad[3] = '=';}
    if (n < 2){quad[2] = '=';}
    for(i=0; i < 4; i++){ret += quad[i];}
  }
  return ret;
}//base64_encode

int FlvToFragNum( FLV_Pack * tag ) {
  int Timestamp = (tag->data[7] << 24 ) + (tag->data[4] << 16 ) + (tag->data[5] << 8 ) + (tag->data[6] );
  return (Timestamp / 10000) + 1;
}

std::string BuildManifest( std::string MetaData, std::string MovieId, int CurrentMediaTime ) {
  Interface * temp = new Interface;
  std::string Result="<manifest>\n";
  Result += "  <mimeType>video/mp4</mimeType>\n";
  Result += "  <streamType>live</streamType>\n";
  Result += "  <deliveryType>streaming</deliveryType>\n";
  Result += "  <bootstrapInfo profile=\"named\" id=\"bootstrap1\">\n";
  Result += base64_encode(temp->GenerateLiveBootstrap(CurrentMediaTime));
  Result += "  </bootstrapInfo>\n";
  Result += "  <media streamId=\"1\" bootstrapInfoId=\"bootstrap1\" url=\"";
  Result += MovieId;
  Result += "/\">";
  Result += "    <metadata>\n";
  Result += base64_encode(MetaData);
  Result += "    </metadata>\n";
  Result += "  </media>\n";
  Result += "</manifest>\n";
  delete temp;
  return Result;
}

int mainHandler(int CONN_fd){
  int handler = HANDLER_PROGRESSIVE;
  bool ready4data = false;//set to true when streaming starts
  bool inited = false;
  bool progressive_has_sent_header = false;
  int ss;
  std::string streamname;
  std::string FlashBuf;
  std::string FlashMeta;
  bool Flash_ManifestSent = false;
  FLV_Pack * tag = 0;
  HTTPReader HTTP_R, HTTP_S;//HTTP Receiver en HTTP Sender.

  int retval;
  int poller = epoll_create(1);
  int sspoller = epoll_create(1);
  struct epoll_event ev;
  ev.events = EPOLLIN;
  ev.data.fd = CONN_fd;
  epoll_ctl(poller, EPOLL_CTL_ADD, CONN_fd, &ev);
  struct epoll_event events[1];

  std::string Movie = "";
  std::string Quality = "";
  int Segment = -1;
  int ReqFragment = -1;
  int temp;
  int CurrentFragment = -1;

  while (!socketError && !All_Hell_Broke_Loose){
    //only parse input if available or not yet init'ed
    retval = epoll_wait(poller, events, 1, 1);
    if ((retval > 0) || !ready4data){
      if (HTTP_R.ReadSocket(CONN_fd)){
        handler = HANDLER_PROGRESSIVE;
        if ((HTTP_R.url.find("Seg") != std::string::npos) && (HTTP_R.url.find("Frag") != std::string::npos)){handler = HANDLER_FLASH;}
        if (HTTP_R.url.find("f4m") != std::string:npos){handler = HANDLER_FLASH;}
        if (HTTP_R.url == "/crossdomain.xml"){
          handler = HANDLER_NONE;
          HTTP_S.Clean();
          HTTP_S.SetHeader("Content-Type", "text/xml");
          HTTP_S.SetBody("<?xml version=\"1.0\"?><!DOCTYPE cross-domain-policy SYSTEM \"http://www.adobe.com/xml/dtds/cross-domain-policy.dtd\"><cross-domain-policy><allow-access-from domain=\"*\" /><site-control permitted-cross-domain-policies=\"all\"/></cross-domain-policy>");
          std::string tmpresp = HTTP_S.BuildResponse("200", "OK");//geen SetBody = unknown length! Dat willen we hier.
          DDV_write(tmpresp.c_str(), tmpresp.size(), CONN_fd);//schrijf de HTTP response header
          #if DEBUG >= 3
          printf("Sending crossdomain.xml file\n");
          #endif
        }
        if(handler == HANDLER_FLASH){
          if (HTTP_R.url.find("f4m") == std::string:npos){
            Movie = HTTP_R.url.substr(1);
            Movie = Movie.substr(0,Movie.find("/"));
            Quality = HTTP_R.url.substr( HTTP_R.url.find("/",1)+1 );
            Quality = Quality.substr(0, Quality.find("Seg"));
            temp = HTTP_R.url.find("Seg") + 3;
            Segment = atoi( HTTP_R.url.substr(temp,HTTP_R.url.find("-",temp)-temp).c_str());
            temp = HTTP_R.url.find("Frag") + 4;
            ReqFragment = atoi( HTTP_R.url.substr(temp).c_str() );
            #if DEBUG >= 4
            printf( "URL: %s\n", HTTP_R.url.c_str());
            printf( "Movie Identifier: %s\n", Movie.c_str() );
            printf( "Quality Modifier: %s\n", Quality.c_str() );
            printf( "Segment: %d\n", Segment );
            printf( "Fragment: %d\n", ReqFragment );
            #endif
            HTTP_S.Clean();
            HTTP_S.SetHeader("Content-Type","video/mp4");
            //ERIK: Help, plox?
            //HTTP_S.SetBody();//Wrap de FlashBuf?
            std::string tmpresp = HTTP_S.BuildResponse("200", "OK");
            DDV_write(tmpresp.c_str(), tmpresp.size(), CONN_fd);//schrijf de HTTP response header
          }else{
            Movie = HTTP_R.url.substr(1);
            Movie = Movie.substr(0,Movie.find("/"));
          }
          streamname = "/tmp/shared_socket_";
          for (std::string::iterator i=Movie.end()-1; i>=Movie.begin(); --i){
            if (!isalpha(*i) && !isdigit(*i)){
              Movie.erase(i);
            }else{
              *i=tolower(*i);
            }//strip nonalphanumeric
          }
          streamname += Movie;
          ready4data = true;
        }//FLASH handler
        if (handler == HANDLER_PROGRESSIVE){
          //in het geval progressive nemen we aan dat de URL de streamname is, met .flv erachter
          streamname = HTTP_R.url.substr(0, HTTP_R.url.size()-4);//strip de .flv
          for (std::string::iterator i=streamname.end()-1; i>=streamname.begin(); --i){
            if (!isalpha(*i) && !isdigit(*i)){streamname.erase(i);}else{*i=tolower(*i);}//strip nonalphanumeric
          }
          streamname = "/tmp/shared_socket_" + streamname;//dit is dan onze shared_socket
          //normaal zouden we ook een position uitlezen uit de URL, maar bij LIVE streams is dat zinloos
          printf("Streamname: %s\n", streamname.c_str());
          ready4data = true;
        }//PROGRESSIVE handler
        HTTP_R.Clean(); //maak schoon na verwerken voor eventuele volgende requests...
      }
    }
    if (ready4data){
      if (!inited){
        //we are ready, connect the socket!
        ss = DDV_OpenUnix(streamname);
        if (ss <= 0){
          #if DEBUG >= 1
          fprintf(stderr, "Could not connect to server!\n");
          #endif
          socketError = 1;
          break;
        }
        ev.events = EPOLLIN;
        ev.data.fd = ss;
        epoll_ctl(sspoller, EPOLL_CTL_ADD, ss, &ev);
        #if DEBUG >= 3
        fprintf(stderr, "Everything connected, starting to send video data...\n");
        #endif
        inited = true;
      }
      retval = epoll_wait(sspoller, events, 1, 1);
      switch (DDV_ready(ss)){
        case 0:
          socketError = true;
          #if DEBUG >= 1
          fprintf(stderr, "Source socket is disconnected.\n");
          #endif
          break;
        case -1: break;//not ready yet
        default:
          if (FLV_GetPacket(tag, ss)){//able to read a full packet?
            //ERIK: "tag" bevat nu een FLV tag (video, audio, of metadata), de header hebben we al weggelezen, np.
            //ERIK: Dit is het punt waarop je eventueel data mag/kan gaan sturen en/of parsen. Leef je uit.
            //ERIK: je kan een HTTP_S gebruiken om je HTTP request op te bouwen (via SetBody, SetHeader, etc)
            //ERIK: en dan met de .BuildResponse("200", "OK"); call een std::string met de hele response maken, klaar voor versturen
            //ERIK: Note: hergebruik echter NIET de HTTP_R die ik al heb gemaakt hierboven, want er kunnen meerdere requests binnenkomen!
            if (handler == HANDLER_FLASH){
              if(tag->data[0] != 0x12 ) {
                FlashBuf.append(tag->data,tag->len);
              } else {
                FlashMeta = "";
                FlashMeta.append(tag->data,tag->len);
                if( !Flash_ManifestSent ) {
                  HTTP_S.Clean();
                  HTTP_S.SetHeader("Content-Type","text/xml");
                  HTTP_S.SetHeader("Cache-Control","no-cache");
                  HTTP_S.SetBody(BuildManifest(FlashMeta, Movie, 0));
                  std::string tmpresp = HTTP_S.BuildResponse("200", "OK");
                  DDV_write(tmpresp.c_str(), tmpresp.size(), CONN_fd);//schrijf de HTTP response header
                }
              }
            }
            if (handler == HANDLER_PROGRESSIVE){
              if (!progressive_has_sent_header){
                HTTP_S.Clean();//troep opruimen die misschien aanwezig is...
                HTTP_S.SetHeader("Content-Type", "video/x-flv");//FLV files hebben altijd dit content-type.
                std::string tmpresp = HTTP_S.BuildResponse("200", "OK");//geen SetBody = unknown length! Dat willen we hier.
                DDV_write(tmpresp.c_str(), tmpresp.size(), CONN_fd);//schrijf de HTTP response header
                DDV_write(FLVHeader, 13, CONN_fd);//schrijf de FLV header, altijd 13 chars lang
                progressive_has_sent_header = true;
              }
              DDV_write(tag->data, tag->len, CONN_fd);//schrijf deze FLV tag onbewerkt weg
            }//PROGRESSIVE handler
          }
          break;
      }
    }
  }
  close(CONN_fd);
  if (inited) close(ss);
  #if DEBUG >= 1
  if (All_Hell_Broke_Loose){fprintf(stderr, "All Hell Broke Loose\n");}
  fprintf(stderr, "User %i disconnected.\n", CONN_fd);
  if (inited){
    fprintf(stderr, "Status was: inited\n");
  }else{
    if (ready4data){
      fprintf(stderr, "Status was: ready4data\n");
    }else{
      fprintf(stderr, "Status was: connected\n");
    }
  }
  #endif
  return 0;
}

<|endoftext|>


<commit_before>/*
 * Copyright © 2013 Intel Corporation
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */

#include "glsl_parser_extras.h"
#include "ir.h"
#include "ir_uniform.h"
#include "linker.h"
#include "program/hash_table.h"
#include "main/macros.h"

namespace {
   /*
    * Atomic counter as seen by the program.
    */
   struct active_atomic_counter {
      unsigned id;
      ir_variable *var;
   };

   /*
    * Atomic counter buffer referenced by the program.  There is a one
    * to one correspondence between these and the objects that can be
    * queried using glGetActiveAtomicCounterBufferiv().
    */
   struct active_atomic_buffer {
      active_atomic_buffer()
         : counters(0), num_counters(0), stage_references(), size(0)
      {}

      ~active_atomic_buffer()
      {
         free(counters);
      }

      void push_back(unsigned id, ir_variable *var)
      {
         counters = (active_atomic_counter *)
            realloc(counters, sizeof(active_atomic_counter) * (num_counters + 1));

         counters[num_counters].id = id;
         counters[num_counters].var = var;
         num_counters++;
      }

      active_atomic_counter *counters;
      unsigned num_counters;
      unsigned stage_references[MESA_SHADER_STAGES];
      unsigned size;
   };

   int
   cmp_actives(const void *a, const void *b)
   {
      const active_atomic_counter *const first = (active_atomic_counter *) a;
      const active_atomic_counter *const second = (active_atomic_counter *) b;

      return int(first->var->data.atomic.offset) - int(second->var->data.atomic.offset);
   }

   bool
   check_atomic_counters_overlap(const ir_variable *x, const ir_variable *y)
   {
      return ((x->data.atomic.offset >= y->data.atomic.offset &&
               x->data.atomic.offset < y->data.atomic.offset + y->type->atomic_size()) ||
              (y->data.atomic.offset >= x->data.atomic.offset &&
               y->data.atomic.offset < x->data.atomic.offset + x->type->atomic_size()));
   }

   active_atomic_buffer *
   find_active_atomic_counters(struct gl_context *ctx,
                               struct gl_shader_program *prog,
                               unsigned *num_buffers)
   {
      active_atomic_buffer *const buffers =
         new active_atomic_buffer[ctx->Const.MaxAtomicBufferBindings];

      *num_buffers = 0;

      for (unsigned i = 0; i < MESA_SHADER_STAGES; ++i) {
         struct gl_shader *sh = prog->_LinkedShaders[i];
         if (sh == NULL)
            continue;

         foreach_list(node, sh->ir) {
            ir_variable *var = ((ir_instruction *)node)->as_variable();

            if (var && var->type->contains_atomic()) {
               unsigned id = 0;
               bool found = prog->UniformHash->get(id, var->name);
               assert(found);
               (void) found;
               active_atomic_buffer *buf = &buffers[var->data.binding];

               /* If this is the first time the buffer is used, increment
                * the counter of buffers used.
                */
               if (buf->size == 0)
                  (*num_buffers)++;

               buf->push_back(id, var);

               buf->stage_references[i]++;
               buf->size = MAX2(buf->size, var->data.atomic.offset +
                                var->type->atomic_size());
            }
         }
      }

      for (unsigned i = 0; i < ctx->Const.MaxAtomicBufferBindings; i++) {
         if (buffers[i].size == 0)
            continue;

         qsort(buffers[i].counters, buffers[i].num_counters,
               sizeof(active_atomic_counter),
               cmp_actives);

         for (unsigned j = 1; j < buffers[i].num_counters; j++) {
            /* If an overlapping counter found, it must be a reference to the
             * same counter from a different shader stage.
             */
            if (check_atomic_counters_overlap(buffers[i].counters[j-1].var,
                                              buffers[i].counters[j].var)
                && strcmp(buffers[i].counters[j-1].var->name,
                          buffers[i].counters[j].var->name) != 0) {
               linker_error(prog, "Atomic counter %s declared at offset %d "
                            "which is already in use.",
                            buffers[i].counters[j].var->name,
                            buffers[i].counters[j].var->data.atomic.offset);
            }
         }
      }
      return buffers;
   }
}

void
link_assign_atomic_counter_resources(struct gl_context *ctx,
                                     struct gl_shader_program *prog)
{
   unsigned num_buffers;
   active_atomic_buffer *abs =
      find_active_atomic_counters(ctx, prog, &num_buffers);

   prog->AtomicBuffers = rzalloc_array(prog, gl_active_atomic_buffer,
                                       num_buffers);
   prog->NumAtomicBuffers = num_buffers;

   unsigned i = 0;
   for (unsigned binding = 0;
        binding < ctx->Const.MaxAtomicBufferBindings;
        binding++) {

      /* If the binding was not used, skip.
       */
      if (abs[binding].size == 0)
         continue;

      active_atomic_buffer &ab = abs[binding];
      gl_active_atomic_buffer &mab = prog->AtomicBuffers[i];

      /* Assign buffer-specific fields. */
      mab.Binding = binding;
      mab.MinimumSize = ab.size;
      mab.Uniforms = rzalloc_array(prog->AtomicBuffers, GLuint,
                                   ab.num_counters);
      mab.NumUniforms = ab.num_counters;

      /* Assign counter-specific fields. */
      for (unsigned j = 0; j < ab.num_counters; j++) {
         ir_variable *const var = ab.counters[j].var;
         const unsigned id = ab.counters[j].id;
         gl_uniform_storage *const storage = &prog->UniformStorage[id];

         mab.Uniforms[j] = id;
         var->data.atomic.buffer_index = i;
         storage->atomic_buffer_index = i;
         storage->offset = var->data.atomic.offset;
         storage->array_stride = (var->type->is_array() ?
                                  var->type->element_type()->atomic_size() : 0);
      }

      /* Assign stage-specific fields. */
      for (unsigned j = 0; j < MESA_SHADER_STAGES; ++j)
         mab.StageReferences[j] =
            (ab.stage_references[j] ? GL_TRUE : GL_FALSE);

      i++;
   }

   delete [] abs;
   assert(i == num_buffers);
}

void
link_check_atomic_counter_resources(struct gl_context *ctx,
                                    struct gl_shader_program *prog)
{
   unsigned num_buffers;
   active_atomic_buffer *const abs =
      find_active_atomic_counters(ctx, prog, &num_buffers);
   unsigned atomic_counters[MESA_SHADER_STAGES] = {};
   unsigned atomic_buffers[MESA_SHADER_STAGES] = {};
   unsigned total_atomic_counters = 0;
   unsigned total_atomic_buffers = 0;

   /* Sum the required resources.  Note that this counts buffers and
    * counters referenced by several shader stages multiple times
    * against the combined limit -- That's the behavior the spec
    * requires.
    */
   for (unsigned i = 0; i < ctx->Const.MaxAtomicBufferBindings; i++) {
      if (abs[i].size == 0)
         continue;

      for (unsigned j = 0; j < MESA_SHADER_STAGES; ++j) {
         const unsigned n = abs[i].stage_references[j];

         if (n) {
            atomic_counters[j] += n;
            total_atomic_counters += n;
            atomic_buffers[j]++;
            total_atomic_buffers++;
         }
      }
   }

   /* Check that they are within the supported limits. */
   for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
      if (atomic_counters[i] > ctx->Const.Program[i].MaxAtomicCounters)
         linker_error(prog, "Too many %s shader atomic counters",
                      _mesa_shader_stage_to_string(i));

      if (atomic_buffers[i] > ctx->Const.Program[i].MaxAtomicBuffers)
         linker_error(prog, "Too many %s shader atomic counter buffers",
                      _mesa_shader_stage_to_string(i));
   }

   if (total_atomic_counters > ctx->Const.MaxCombinedAtomicCounters)
      linker_error(prog, "Too many combined atomic counters");

   if (total_atomic_buffers > ctx->Const.MaxCombinedAtomicBuffers)
      linker_error(prog, "Too many combined atomic buffers");

   delete [] abs;
}
<commit_msg>glsl: Add missing null check in push_back()<commit_after>/*
 * Copyright © 2013 Intel Corporation
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */

#include "glsl_parser_extras.h"
#include "ir.h"
#include "ir_uniform.h"
#include "linker.h"
#include "program/hash_table.h"
#include "main/macros.h"

namespace {
   /*
    * Atomic counter as seen by the program.
    */
   struct active_atomic_counter {
      unsigned id;
      ir_variable *var;
   };

   /*
    * Atomic counter buffer referenced by the program.  There is a one
    * to one correspondence between these and the objects that can be
    * queried using glGetActiveAtomicCounterBufferiv().
    */
   struct active_atomic_buffer {
      active_atomic_buffer()
         : counters(0), num_counters(0), stage_references(), size(0)
      {}

      ~active_atomic_buffer()
      {
         free(counters);
      }

      void push_back(unsigned id, ir_variable *var)
      {
         active_atomic_counter *new_counters;

         new_counters = (active_atomic_counter *)
            realloc(counters, sizeof(active_atomic_counter) *
                    (num_counters + 1));

         if (new_counters == NULL) {
            _mesa_error_no_memory(__func__);
            return;
         }

         counters = new_counters;
         counters[num_counters].id = id;
         counters[num_counters].var = var;
         num_counters++;
      }

      active_atomic_counter *counters;
      unsigned num_counters;
      unsigned stage_references[MESA_SHADER_STAGES];
      unsigned size;
   };

   int
   cmp_actives(const void *a, const void *b)
   {
      const active_atomic_counter *const first = (active_atomic_counter *) a;
      const active_atomic_counter *const second = (active_atomic_counter *) b;

      return int(first->var->data.atomic.offset) - int(second->var->data.atomic.offset);
   }

   bool
   check_atomic_counters_overlap(const ir_variable *x, const ir_variable *y)
   {
      return ((x->data.atomic.offset >= y->data.atomic.offset &&
               x->data.atomic.offset < y->data.atomic.offset + y->type->atomic_size()) ||
              (y->data.atomic.offset >= x->data.atomic.offset &&
               y->data.atomic.offset < x->data.atomic.offset + x->type->atomic_size()));
   }

   active_atomic_buffer *
   find_active_atomic_counters(struct gl_context *ctx,
                               struct gl_shader_program *prog,
                               unsigned *num_buffers)
   {
      active_atomic_buffer *const buffers =
         new active_atomic_buffer[ctx->Const.MaxAtomicBufferBindings];

      *num_buffers = 0;

      for (unsigned i = 0; i < MESA_SHADER_STAGES; ++i) {
         struct gl_shader *sh = prog->_LinkedShaders[i];
         if (sh == NULL)
            continue;

         foreach_list(node, sh->ir) {
            ir_variable *var = ((ir_instruction *)node)->as_variable();

            if (var && var->type->contains_atomic()) {
               unsigned id = 0;
               bool found = prog->UniformHash->get(id, var->name);
               assert(found);
               (void) found;
               active_atomic_buffer *buf = &buffers[var->data.binding];

               /* If this is the first time the buffer is used, increment
                * the counter of buffers used.
                */
               if (buf->size == 0)
                  (*num_buffers)++;

               buf->push_back(id, var);

               buf->stage_references[i]++;
               buf->size = MAX2(buf->size, var->data.atomic.offset +
                                var->type->atomic_size());
            }
         }
      }

      for (unsigned i = 0; i < ctx->Const.MaxAtomicBufferBindings; i++) {
         if (buffers[i].size == 0)
            continue;

         qsort(buffers[i].counters, buffers[i].num_counters,
               sizeof(active_atomic_counter),
               cmp_actives);

         for (unsigned j = 1; j < buffers[i].num_counters; j++) {
            /* If an overlapping counter found, it must be a reference to the
             * same counter from a different shader stage.
             */
            if (check_atomic_counters_overlap(buffers[i].counters[j-1].var,
                                              buffers[i].counters[j].var)
                && strcmp(buffers[i].counters[j-1].var->name,
                          buffers[i].counters[j].var->name) != 0) {
               linker_error(prog, "Atomic counter %s declared at offset %d "
                            "which is already in use.",
                            buffers[i].counters[j].var->name,
                            buffers[i].counters[j].var->data.atomic.offset);
            }
         }
      }
      return buffers;
   }
}

void
link_assign_atomic_counter_resources(struct gl_context *ctx,
                                     struct gl_shader_program *prog)
{
   unsigned num_buffers;
   active_atomic_buffer *abs =
      find_active_atomic_counters(ctx, prog, &num_buffers);

   prog->AtomicBuffers = rzalloc_array(prog, gl_active_atomic_buffer,
                                       num_buffers);
   prog->NumAtomicBuffers = num_buffers;

   unsigned i = 0;
   for (unsigned binding = 0;
        binding < ctx->Const.MaxAtomicBufferBindings;
        binding++) {

      /* If the binding was not used, skip.
       */
      if (abs[binding].size == 0)
         continue;

      active_atomic_buffer &ab = abs[binding];
      gl_active_atomic_buffer &mab = prog->AtomicBuffers[i];

      /* Assign buffer-specific fields. */
      mab.Binding = binding;
      mab.MinimumSize = ab.size;
      mab.Uniforms = rzalloc_array(prog->AtomicBuffers, GLuint,
                                   ab.num_counters);
      mab.NumUniforms = ab.num_counters;

      /* Assign counter-specific fields. */
      for (unsigned j = 0; j < ab.num_counters; j++) {
         ir_variable *const var = ab.counters[j].var;
         const unsigned id = ab.counters[j].id;
         gl_uniform_storage *const storage = &prog->UniformStorage[id];

         mab.Uniforms[j] = id;
         var->data.atomic.buffer_index = i;
         storage->atomic_buffer_index = i;
         storage->offset = var->data.atomic.offset;
         storage->array_stride = (var->type->is_array() ?
                                  var->type->element_type()->atomic_size() : 0);
      }

      /* Assign stage-specific fields. */
      for (unsigned j = 0; j < MESA_SHADER_STAGES; ++j)
         mab.StageReferences[j] =
            (ab.stage_references[j] ? GL_TRUE : GL_FALSE);

      i++;
   }

   delete [] abs;
   assert(i == num_buffers);
}

void
link_check_atomic_counter_resources(struct gl_context *ctx,
                                    struct gl_shader_program *prog)
{
   unsigned num_buffers;
   active_atomic_buffer *const abs =
      find_active_atomic_counters(ctx, prog, &num_buffers);
   unsigned atomic_counters[MESA_SHADER_STAGES] = {};
   unsigned atomic_buffers[MESA_SHADER_STAGES] = {};
   unsigned total_atomic_counters = 0;
   unsigned total_atomic_buffers = 0;

   /* Sum the required resources.  Note that this counts buffers and
    * counters referenced by several shader stages multiple times
    * against the combined limit -- That's the behavior the spec
    * requires.
    */
   for (unsigned i = 0; i < ctx->Const.MaxAtomicBufferBindings; i++) {
      if (abs[i].size == 0)
         continue;

      for (unsigned j = 0; j < MESA_SHADER_STAGES; ++j) {
         const unsigned n = abs[i].stage_references[j];

         if (n) {
            atomic_counters[j] += n;
            total_atomic_counters += n;
            atomic_buffers[j]++;
            total_atomic_buffers++;
         }
      }
   }

   /* Check that they are within the supported limits. */
   for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
      if (atomic_counters[i] > ctx->Const.Program[i].MaxAtomicCounters)
         linker_error(prog, "Too many %s shader atomic counters",
                      _mesa_shader_stage_to_string(i));

      if (atomic_buffers[i] > ctx->Const.Program[i].MaxAtomicBuffers)
         linker_error(prog, "Too many %s shader atomic counter buffers",
                      _mesa_shader_stage_to_string(i));
   }

   if (total_atomic_counters > ctx->Const.MaxCombinedAtomicCounters)
      linker_error(prog, "Too many combined atomic counters");

   if (total_atomic_buffers > ctx->Const.MaxCombinedAtomicBuffers)
      linker_error(prog, "Too many combined atomic buffers");

   delete [] abs;
}
<|endoftext|>


<commit_before>/*
 * Author: Jon Trulson <jtrulson@ics.com>
 * Copyright (c) 2015 Intel Corporation.
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <iostream>

#include "grovewfs.h"

using namespace upm;
using namespace std;

GroveWFS::GroveWFS(int pin)
{
  if ( !(m_gpio = mraa_gpio_init(pin)) )
    {
      cerr << __FUNCTION__ << ": mraa_gpio_init() failed" << endl;
      return;
    }

  mraa_gpio_dir(m_gpio, MRAA_GPIO_IN);

  initClock();
  m_flowCounter = 0;
  m_isrInstalled = false;
}

GroveWFS::~GroveWFS()
{
  if (m_isrInstalled)
    stopFlowCounter();

  mraa_gpio_close(m_gpio);
}

void GroveWFS::initClock()
{
  gettimeofday(&m_startTime, NULL);
}

uint32_t GroveWFS::getMillis()
{
  struct timeval elapsed, now;
  uint32_t elapse;

  // get current time
  gettimeofday(&now, NULL);

  // compute the delta since m_startTime
  if( (elapsed.tv_usec = now.tv_usec - m_startTime.tv_usec) < 0 )
    {
      elapsed.tv_usec += 1000000;
      elapsed.tv_sec = now.tv_sec - m_startTime.tv_sec - 1;
    }
  else
    {
      elapsed.tv_sec = now.tv_sec - m_startTime.tv_sec;
    }

  elapse = (uint32_t)((elapsed.tv_sec * 1000) + (elapsed.tv_usec / 1000));

  // never return 0
  if (elapse == 0)
    elapse = 1;

  return elapse;
}

void GroveWFS::startFlowCounter()
{
  initClock();
  // install our interrupt handler
  mraa_gpio_isr(m_gpio, MRAA_GPIO_EDGE_RISING,
                &flowISR, this);

  m_isrInstalled = true;
}

void GroveWFS::stopFlowCounter()
{
  // remove the interrupt handler
  mraa_gpio_isr_exit(m_gpio);

  m_isrInstalled = false;
}

void GroveWFS::flowISR(void *ctx)
{
  upm::GroveWFS *This = (upm::GroveWFS *)ctx;
  This->m_flowCounter++;
}

float GroveWFS::flowRate()
{
  uint32_t millis = getMillis();
  uint32_t flow = flowCounter();

  // 7.5 comes from the seeedstudio page, see the confusing datasheet :)
  float flowRate = (float(flow) * 7.5) / ((float(millis) / 1000.0) * 60.0);

  return flowRate;
}
<commit_msg>grovewfs: throw exception(s) on fatal errors<commit_after>/*
 * Author: Jon Trulson <jtrulson@ics.com>
 * Copyright (c) 2015 Intel Corporation.
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <iostream>
#include <string>
#include <stdexcept>

#include "grovewfs.h"

using namespace upm;
using namespace std;

GroveWFS::GroveWFS(int pin)
{
  if ( !(m_gpio = mraa_gpio_init(pin)) )
    {
      throw std::invalid_argument(std::string(__FUNCTION__) +
                                  ": mraa_gpio_init() failed, invalid pin?");
      return;
    }

  mraa_gpio_dir(m_gpio, MRAA_GPIO_IN);

  initClock();
  m_flowCounter = 0;
  m_isrInstalled = false;
}

GroveWFS::~GroveWFS()
{
  if (m_isrInstalled)
    stopFlowCounter();

  mraa_gpio_close(m_gpio);
}

void GroveWFS::initClock()
{
  gettimeofday(&m_startTime, NULL);
}

uint32_t GroveWFS::getMillis()
{
  struct timeval elapsed, now;
  uint32_t elapse;

  // get current time
  gettimeofday(&now, NULL);

  // compute the delta since m_startTime
  if( (elapsed.tv_usec = now.tv_usec - m_startTime.tv_usec) < 0 )
    {
      elapsed.tv_usec += 1000000;
      elapsed.tv_sec = now.tv_sec - m_startTime.tv_sec - 1;
    }
  else
    {
      elapsed.tv_sec = now.tv_sec - m_startTime.tv_sec;
    }

  elapse = (uint32_t)((elapsed.tv_sec * 1000) + (elapsed.tv_usec / 1000));

  // never return 0
  if (elapse == 0)
    elapse = 1;

  return elapse;
}

void GroveWFS::startFlowCounter()
{
  initClock();
  // install our interrupt handler
  mraa_gpio_isr(m_gpio, MRAA_GPIO_EDGE_RISING,
                &flowISR, this);

  m_isrInstalled = true;
}

void GroveWFS::stopFlowCounter()
{
  // remove the interrupt handler
  mraa_gpio_isr_exit(m_gpio);

  m_isrInstalled = false;
}

void GroveWFS::flowISR(void *ctx)
{
  upm::GroveWFS *This = (upm::GroveWFS *)ctx;
  This->m_flowCounter++;
}

float GroveWFS::flowRate()
{
  uint32_t millis = getMillis();
  uint32_t flow = flowCounter();

  // 7.5 comes from the seeedstudio page, see the confusing datasheet :)
  float flowRate = (float(flow) * 7.5) / ((float(millis) / 1000.0) * 60.0);

  return flowRate;
}
<|endoftext|>


<commit_before>//===-- tsan_platform_linux.cc --------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is a part of ThreadSanitizer (TSan), a race detector.
//
// Linux-specific code.
//===----------------------------------------------------------------------===//

#include "sanitizer_common/sanitizer_platform.h"
#if SANITIZER_LINUX

#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_libc.h"
#include "sanitizer_common/sanitizer_procmaps.h"
#include "sanitizer_common/sanitizer_stoptheworld.h"
#include "tsan_platform.h"
#include "tsan_rtl.h"
#include "tsan_flags.h"

#include <fcntl.h>
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <sys/mman.h>
#include <sys/prctl.h>
#include <sys/syscall.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/resource.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include <sched.h>
#include <dlfcn.h>
#define __need_res_state
#include <resolv.h>
#include <malloc.h>

#ifdef sa_handler
# undef sa_handler
#endif

#ifdef sa_sigaction
# undef sa_sigaction
#endif

extern "C" struct mallinfo __libc_mallinfo();

namespace __tsan {

const uptr kPageSize = 4096;

void FillProfileCallback(uptr start, uptr rss, bool file,
                         uptr *mem, uptr stats_size) {
  CHECK_EQ(7, stats_size);
  mem[6] += rss;  // total
  start >>= 40;
  if (start < 0x10)  // shadow
    mem[0] += rss;
  else if (start >= 0x20 && start < 0x30)  // compat modules
    mem[file ? 1 : 2] += rss;
  else if (start >= 0x7e)  // modules
    mem[file ? 1 : 2] += rss;
  else if (start >= 0x60 && start < 0x62)  // traces
    mem[3] += rss;
  else if (start >= 0x7d && start < 0x7e)  // heap
    mem[4] += rss;
  else  // other
    mem[5] += rss;
}

void WriteMemoryProfile(char *buf, uptr buf_size) {
  uptr mem[7] = {};
  __sanitizer::GetMemoryProfile(FillProfileCallback, mem, 7);
  char *buf_pos = buf;
  char *buf_end = buf + buf_size;
  buf_pos += internal_snprintf(buf_pos, buf_end - buf_pos,
      "RSS %zd MB: shadow:%zd file:%zd mmap:%zd trace:%zd heap:%zd other:%zd\n",
      mem[6] >> 20, mem[0] >> 20, mem[1] >> 20, mem[2] >> 20,
      mem[3] >> 20, mem[4] >> 20, mem[5] >> 20);
  struct mallinfo mi = __libc_mallinfo();
  buf_pos += internal_snprintf(buf_pos, buf_end - buf_pos,
      "mallinfo: arena=%d mmap=%d fordblks=%d keepcost=%d\n",
      mi.arena >> 20, mi.hblkhd >> 20, mi.fordblks >> 20, mi.keepcost >> 20);
}

uptr GetRSS() {
  uptr mem[7] = {};
  __sanitizer::GetMemoryProfile(FillProfileCallback, mem, 7);
  return mem[6];
}

void FlushShadowMemoryCallback(
    const SuspendedThreadsList &suspended_threads_list,
    void *argument) {
  FlushUnneededShadowMemory(kLinuxShadowBeg, kLinuxShadowEnd - kLinuxShadowBeg);
}

void FlushShadowMemory() {
  StopTheWorld(FlushShadowMemoryCallback, 0);
}

#ifndef TSAN_GO
static void ProtectRange(uptr beg, uptr end) {
  CHECK_LE(beg, end);
  if (beg == end)
    return;
  if (beg != (uptr)Mprotect(beg, end - beg)) {
    Printf("FATAL: ThreadSanitizer can not protect [%zx,%zx]\n", beg, end);
    Printf("FATAL: Make sure you are not using unlimited stack\n");
    Die();
  }
}
#endif

#ifndef TSAN_GO
// Mark shadow for .rodata sections with the special kShadowRodata marker.
// Accesses to .rodata can't race, so this saves time, memory and trace space.
static void MapRodata() {
  // First create temp file.
  const char *tmpdir = GetEnv("TMPDIR");
  if (tmpdir == 0)
    tmpdir = GetEnv("TEST_TMPDIR");
#ifdef P_tmpdir
  if (tmpdir == 0)
    tmpdir = P_tmpdir;
#endif
  if (tmpdir == 0)
    return;
  char name[256];
  internal_snprintf(name, sizeof(name), "%s/tsan.rodata.%d",
                    tmpdir, (int)internal_getpid());
  uptr openrv = internal_open(name, O_RDWR | O_CREAT | O_EXCL, 0600);
  if (internal_iserror(openrv))
    return;
  internal_unlink(name);  // Unlink it now, so that we can reuse the buffer.
  fd_t fd = openrv;
  // Fill the file with kShadowRodata.
  const uptr kMarkerSize = 512 * 1024 / sizeof(u64);
  InternalScopedBuffer<u64> marker(kMarkerSize);
  for (u64 *p = marker.data(); p < marker.data() + kMarkerSize; p++)
    *p = kShadowRodata;
  internal_write(fd, marker.data(), marker.size());
  // Map the file into memory.
  uptr page = internal_mmap(0, kPageSize, PROT_READ | PROT_WRITE,
                            MAP_PRIVATE | MAP_ANONYMOUS, fd, 0);
  if (internal_iserror(page)) {
    internal_close(fd);
    return;
  }
  // Map the file into shadow of .rodata sections.
  MemoryMappingLayout proc_maps(/*cache_enabled*/true);
  uptr start, end, offset, prot;
  // Reusing the buffer 'name'.
  while (proc_maps.Next(&start, &end, &offset, name, ARRAY_SIZE(name), &prot)) {
    if (name[0] != 0 && name[0] != '['
        && (prot & MemoryMappingLayout::kProtectionRead)
        && (prot & MemoryMappingLayout::kProtectionExecute)
        && !(prot & MemoryMappingLayout::kProtectionWrite)
        && IsAppMem(start)) {
      // Assume it's .rodata
      char *shadow_start = (char*)MemToShadow(start);
      char *shadow_end = (char*)MemToShadow(end);
      for (char *p = shadow_start; p < shadow_end; p += marker.size()) {
        internal_mmap(p, Min<uptr>(marker.size(), shadow_end - p),
                      PROT_READ, MAP_PRIVATE | MAP_FIXED, fd, 0);
      }
    }
  }
  internal_close(fd);
}

void InitializeShadowMemory() {
  uptr shadow = (uptr)MmapFixedNoReserve(kLinuxShadowBeg,
    kLinuxShadowEnd - kLinuxShadowBeg);
  if (shadow != kLinuxShadowBeg) {
    Printf("FATAL: ThreadSanitizer can not mmap the shadow memory\n");
    Printf("FATAL: Make sure to compile with -fPIE and "
               "to link with -pie (%p, %p).\n", shadow, kLinuxShadowBeg);
    Die();
  }
  const uptr kClosedLowBeg  = 0x200000;
  const uptr kClosedLowEnd  = kLinuxShadowBeg - 1;
  const uptr kClosedMidBeg = kLinuxShadowEnd + 1;
  const uptr kClosedMidEnd = min(kLinuxAppMemBeg, kTraceMemBegin);
  ProtectRange(kClosedLowBeg, kClosedLowEnd);
  ProtectRange(kClosedMidBeg, kClosedMidEnd);
  DPrintf("kClosedLow   %zx-%zx (%zuGB)\n",
      kClosedLowBeg, kClosedLowEnd, (kClosedLowEnd - kClosedLowBeg) >> 30);
  DPrintf("kLinuxShadow %zx-%zx (%zuGB)\n",
      kLinuxShadowBeg, kLinuxShadowEnd,
      (kLinuxShadowEnd - kLinuxShadowBeg) >> 30);
  DPrintf("kClosedMid   %zx-%zx (%zuGB)\n",
      kClosedMidBeg, kClosedMidEnd, (kClosedMidEnd - kClosedMidBeg) >> 30);
  DPrintf("kLinuxAppMem %zx-%zx (%zuGB)\n",
      kLinuxAppMemBeg, kLinuxAppMemEnd,
      (kLinuxAppMemEnd - kLinuxAppMemBeg) >> 30);
  DPrintf("stack        %zx\n", (uptr)&shadow);

  MapRodata();
}
#endif

static uptr g_data_start;
static uptr g_data_end;

#ifndef TSAN_GO
static void CheckPIE() {
  // Ensure that the binary is indeed compiled with -pie.
  MemoryMappingLayout proc_maps(true);
  uptr start, end;
  if (proc_maps.Next(&start, &end,
                     /*offset*/0, /*filename*/0, /*filename_size*/0,
                     /*protection*/0)) {
    if ((u64)start < kLinuxAppMemBeg) {
      Printf("FATAL: ThreadSanitizer can not mmap the shadow memory ("
             "something is mapped at 0x%zx < 0x%zx)\n",
             start, kLinuxAppMemBeg);
      Printf("FATAL: Make sure to compile with -fPIE"
             " and to link with -pie.\n");
      Die();
    }
  }
}

static void InitDataSeg() {
  MemoryMappingLayout proc_maps(true);
  uptr start, end, offset;
  char name[128];
  bool prev_is_data = false;
  while (proc_maps.Next(&start, &end, &offset, name, ARRAY_SIZE(name),
                        /*protection*/ 0)) {
    DPrintf("%p-%p %p %s\n", start, end, offset, name);
    bool is_data = offset != 0 && name[0] != 0;
    // BSS may get merged with [heap] in /proc/self/maps. This is not very
    // reliable.
    bool is_bss = offset == 0 &&
      (name[0] == 0 || internal_strcmp(name, "[heap]") == 0) && prev_is_data;
    if (g_data_start == 0 && is_data)
      g_data_start = start;
    if (is_bss)
      g_data_end = end;
    prev_is_data = is_data;
  }
  DPrintf("guessed data_start=%p data_end=%p\n",  g_data_start, g_data_end);
  CHECK_LT(g_data_start, g_data_end);
  CHECK_GE((uptr)&g_data_start, g_data_start);
  CHECK_LT((uptr)&g_data_start, g_data_end);
}

#endif  // #ifndef TSAN_GO

static rlim_t getlim(int res) {
  rlimit rlim;
  CHECK_EQ(0, getrlimit(res, &rlim));
  return rlim.rlim_cur;
}

static void setlim(int res, rlim_t lim) {
  // The following magic is to prevent clang from replacing it with memset.
  volatile rlimit rlim;
  rlim.rlim_cur = lim;
  rlim.rlim_max = lim;
  setrlimit(res, (rlimit*)&rlim);
}

const char *InitializePlatform() {
  void *p = 0;
  if (sizeof(p) == 8) {
    // Disable core dumps, dumping of 16TB usually takes a bit long.
    setlim(RLIMIT_CORE, 0);
  }

  // Go maps shadow memory lazily and works fine with limited address space.
  // Unlimited stack is not a problem as well, because the executable
  // is not compiled with -pie.
  if (kCppMode) {
    bool reexec = false;
    // TSan doesn't play well with unlimited stack size (as stack
    // overlaps with shadow memory). If we detect unlimited stack size,
    // we re-exec the program with limited stack size as a best effort.
    if (getlim(RLIMIT_STACK) == (rlim_t)-1) {
      const uptr kMaxStackSize = 32 * 1024 * 1024;
      VReport(1, "Program is run with unlimited stack size, which wouldn't "
                 "work with ThreadSanitizer.\n"
                 "Re-execing with stack size limited to %zd bytes.\n",
              kMaxStackSize);
      SetStackSizeLimitInBytes(kMaxStackSize);
      reexec = true;
    }

    if (getlim(RLIMIT_AS) != (rlim_t)-1) {
      Report("WARNING: Program is run with limited virtual address space,"
             " which wouldn't work with ThreadSanitizer.\n");
      Report("Re-execing with unlimited virtual address space.\n");
      setlim(RLIMIT_AS, -1);
      reexec = true;
    }
    if (reexec)
      ReExec();
  }

#ifndef TSAN_GO
  CheckPIE();
  InitTlsSize();
  InitDataSeg();
#endif
  return GetEnv(kTsanOptionsEnv);
}

bool IsGlobalVar(uptr addr) {
  return g_data_start && addr >= g_data_start && addr < g_data_end;
}

#ifndef TSAN_GO
// Extract file descriptors passed to glibc internal __res_iclose function.
// This is required to properly "close" the fds, because we do not see internal
// closes within glibc. The code is a pure hack.
int ExtractResolvFDs(void *state, int *fds, int nfd) {
  int cnt = 0;
  __res_state *statp = (__res_state*)state;
  for (int i = 0; i < MAXNS && cnt < nfd; i++) {
    if (statp->_u._ext.nsaddrs[i] && statp->_u._ext.nssocks[i] != -1)
      fds[cnt++] = statp->_u._ext.nssocks[i];
  }
  return cnt;
}

// Extract file descriptors passed via UNIX domain sockets.
// This is requried to properly handle "open" of these fds.
// see 'man recvmsg' and 'man 3 cmsg'.
int ExtractRecvmsgFDs(void *msgp, int *fds, int nfd) {
  int res = 0;
  msghdr *msg = (msghdr*)msgp;
  struct cmsghdr *cmsg = CMSG_FIRSTHDR(msg);
  for (; cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {
    if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS)
      continue;
    int n = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(fds[0]);
    for (int i = 0; i < n; i++) {
      fds[res++] = ((int*)CMSG_DATA(cmsg))[i];
      if (res == nfd)
        return res;
    }
  }
  return res;
}
#endif

}  // namespace __tsan

#endif  // SANITIZER_LINUX
<commit_msg>tsan: fix another compiler-injected memset newer gcc inserts memset here<commit_after>//===-- tsan_platform_linux.cc --------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is a part of ThreadSanitizer (TSan), a race detector.
//
// Linux-specific code.
//===----------------------------------------------------------------------===//

#include "sanitizer_common/sanitizer_platform.h"
#if SANITIZER_LINUX

#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_libc.h"
#include "sanitizer_common/sanitizer_procmaps.h"
#include "sanitizer_common/sanitizer_stoptheworld.h"
#include "tsan_platform.h"
#include "tsan_rtl.h"
#include "tsan_flags.h"

#include <fcntl.h>
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <sys/mman.h>
#include <sys/prctl.h>
#include <sys/syscall.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/resource.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include <sched.h>
#include <dlfcn.h>
#define __need_res_state
#include <resolv.h>
#include <malloc.h>

#ifdef sa_handler
# undef sa_handler
#endif

#ifdef sa_sigaction
# undef sa_sigaction
#endif

extern "C" struct mallinfo __libc_mallinfo();

namespace __tsan {

const uptr kPageSize = 4096;

void FillProfileCallback(uptr start, uptr rss, bool file,
                         uptr *mem, uptr stats_size) {
  CHECK_EQ(7, stats_size);
  mem[6] += rss;  // total
  start >>= 40;
  if (start < 0x10)  // shadow
    mem[0] += rss;
  else if (start >= 0x20 && start < 0x30)  // compat modules
    mem[file ? 1 : 2] += rss;
  else if (start >= 0x7e)  // modules
    mem[file ? 1 : 2] += rss;
  else if (start >= 0x60 && start < 0x62)  // traces
    mem[3] += rss;
  else if (start >= 0x7d && start < 0x7e)  // heap
    mem[4] += rss;
  else  // other
    mem[5] += rss;
}

void WriteMemoryProfile(char *buf, uptr buf_size) {
  uptr mem[7] = {};
  __sanitizer::GetMemoryProfile(FillProfileCallback, mem, 7);
  char *buf_pos = buf;
  char *buf_end = buf + buf_size;
  buf_pos += internal_snprintf(buf_pos, buf_end - buf_pos,
      "RSS %zd MB: shadow:%zd file:%zd mmap:%zd trace:%zd heap:%zd other:%zd\n",
      mem[6] >> 20, mem[0] >> 20, mem[1] >> 20, mem[2] >> 20,
      mem[3] >> 20, mem[4] >> 20, mem[5] >> 20);
  struct mallinfo mi = __libc_mallinfo();
  buf_pos += internal_snprintf(buf_pos, buf_end - buf_pos,
      "mallinfo: arena=%d mmap=%d fordblks=%d keepcost=%d\n",
      mi.arena >> 20, mi.hblkhd >> 20, mi.fordblks >> 20, mi.keepcost >> 20);
}

uptr GetRSS() {
  uptr mem[7] = {};
  __sanitizer::GetMemoryProfile(FillProfileCallback, mem, 7);
  return mem[6];
}

void FlushShadowMemoryCallback(
    const SuspendedThreadsList &suspended_threads_list,
    void *argument) {
  FlushUnneededShadowMemory(kLinuxShadowBeg, kLinuxShadowEnd - kLinuxShadowBeg);
}

void FlushShadowMemory() {
  StopTheWorld(FlushShadowMemoryCallback, 0);
}

#ifndef TSAN_GO
static void ProtectRange(uptr beg, uptr end) {
  CHECK_LE(beg, end);
  if (beg == end)
    return;
  if (beg != (uptr)Mprotect(beg, end - beg)) {
    Printf("FATAL: ThreadSanitizer can not protect [%zx,%zx]\n", beg, end);
    Printf("FATAL: Make sure you are not using unlimited stack\n");
    Die();
  }
}
#endif

#ifndef TSAN_GO
// Mark shadow for .rodata sections with the special kShadowRodata marker.
// Accesses to .rodata can't race, so this saves time, memory and trace space.
static void MapRodata() {
  // First create temp file.
  const char *tmpdir = GetEnv("TMPDIR");
  if (tmpdir == 0)
    tmpdir = GetEnv("TEST_TMPDIR");
#ifdef P_tmpdir
  if (tmpdir == 0)
    tmpdir = P_tmpdir;
#endif
  if (tmpdir == 0)
    return;
  char name[256];
  internal_snprintf(name, sizeof(name), "%s/tsan.rodata.%d",
                    tmpdir, (int)internal_getpid());
  uptr openrv = internal_open(name, O_RDWR | O_CREAT | O_EXCL, 0600);
  if (internal_iserror(openrv))
    return;
  internal_unlink(name);  // Unlink it now, so that we can reuse the buffer.
  fd_t fd = openrv;
  // Fill the file with kShadowRodata.
  const uptr kMarkerSize = 512 * 1024 / sizeof(u64);
  InternalScopedBuffer<u64> marker(kMarkerSize);
  // volatile to prevent insertion of memset
  for (volatile u64 *p = marker.data(); p < marker.data() + kMarkerSize; p++)
    *p = kShadowRodata;
  internal_write(fd, marker.data(), marker.size());
  // Map the file into memory.
  uptr page = internal_mmap(0, kPageSize, PROT_READ | PROT_WRITE,
                            MAP_PRIVATE | MAP_ANONYMOUS, fd, 0);
  if (internal_iserror(page)) {
    internal_close(fd);
    return;
  }
  // Map the file into shadow of .rodata sections.
  MemoryMappingLayout proc_maps(/*cache_enabled*/true);
  uptr start, end, offset, prot;
  // Reusing the buffer 'name'.
  while (proc_maps.Next(&start, &end, &offset, name, ARRAY_SIZE(name), &prot)) {
    if (name[0] != 0 && name[0] != '['
        && (prot & MemoryMappingLayout::kProtectionRead)
        && (prot & MemoryMappingLayout::kProtectionExecute)
        && !(prot & MemoryMappingLayout::kProtectionWrite)
        && IsAppMem(start)) {
      // Assume it's .rodata
      char *shadow_start = (char*)MemToShadow(start);
      char *shadow_end = (char*)MemToShadow(end);
      for (char *p = shadow_start; p < shadow_end; p += marker.size()) {
        internal_mmap(p, Min<uptr>(marker.size(), shadow_end - p),
                      PROT_READ, MAP_PRIVATE | MAP_FIXED, fd, 0);
      }
    }
  }
  internal_close(fd);
}

void InitializeShadowMemory() {
  uptr shadow = (uptr)MmapFixedNoReserve(kLinuxShadowBeg,
    kLinuxShadowEnd - kLinuxShadowBeg);
  if (shadow != kLinuxShadowBeg) {
    Printf("FATAL: ThreadSanitizer can not mmap the shadow memory\n");
    Printf("FATAL: Make sure to compile with -fPIE and "
               "to link with -pie (%p, %p).\n", shadow, kLinuxShadowBeg);
    Die();
  }
  const uptr kClosedLowBeg  = 0x200000;
  const uptr kClosedLowEnd  = kLinuxShadowBeg - 1;
  const uptr kClosedMidBeg = kLinuxShadowEnd + 1;
  const uptr kClosedMidEnd = min(kLinuxAppMemBeg, kTraceMemBegin);
  ProtectRange(kClosedLowBeg, kClosedLowEnd);
  ProtectRange(kClosedMidBeg, kClosedMidEnd);
  DPrintf("kClosedLow   %zx-%zx (%zuGB)\n",
      kClosedLowBeg, kClosedLowEnd, (kClosedLowEnd - kClosedLowBeg) >> 30);
  DPrintf("kLinuxShadow %zx-%zx (%zuGB)\n",
      kLinuxShadowBeg, kLinuxShadowEnd,
      (kLinuxShadowEnd - kLinuxShadowBeg) >> 30);
  DPrintf("kClosedMid   %zx-%zx (%zuGB)\n",
      kClosedMidBeg, kClosedMidEnd, (kClosedMidEnd - kClosedMidBeg) >> 30);
  DPrintf("kLinuxAppMem %zx-%zx (%zuGB)\n",
      kLinuxAppMemBeg, kLinuxAppMemEnd,
      (kLinuxAppMemEnd - kLinuxAppMemBeg) >> 30);
  DPrintf("stack        %zx\n", (uptr)&shadow);

  MapRodata();
}
#endif

static uptr g_data_start;
static uptr g_data_end;

#ifndef TSAN_GO
static void CheckPIE() {
  // Ensure that the binary is indeed compiled with -pie.
  MemoryMappingLayout proc_maps(true);
  uptr start, end;
  if (proc_maps.Next(&start, &end,
                     /*offset*/0, /*filename*/0, /*filename_size*/0,
                     /*protection*/0)) {
    if ((u64)start < kLinuxAppMemBeg) {
      Printf("FATAL: ThreadSanitizer can not mmap the shadow memory ("
             "something is mapped at 0x%zx < 0x%zx)\n",
             start, kLinuxAppMemBeg);
      Printf("FATAL: Make sure to compile with -fPIE"
             " and to link with -pie.\n");
      Die();
    }
  }
}

static void InitDataSeg() {
  MemoryMappingLayout proc_maps(true);
  uptr start, end, offset;
  char name[128];
  bool prev_is_data = false;
  while (proc_maps.Next(&start, &end, &offset, name, ARRAY_SIZE(name),
                        /*protection*/ 0)) {
    DPrintf("%p-%p %p %s\n", start, end, offset, name);
    bool is_data = offset != 0 && name[0] != 0;
    // BSS may get merged with [heap] in /proc/self/maps. This is not very
    // reliable.
    bool is_bss = offset == 0 &&
      (name[0] == 0 || internal_strcmp(name, "[heap]") == 0) && prev_is_data;
    if (g_data_start == 0 && is_data)
      g_data_start = start;
    if (is_bss)
      g_data_end = end;
    prev_is_data = is_data;
  }
  DPrintf("guessed data_start=%p data_end=%p\n",  g_data_start, g_data_end);
  CHECK_LT(g_data_start, g_data_end);
  CHECK_GE((uptr)&g_data_start, g_data_start);
  CHECK_LT((uptr)&g_data_start, g_data_end);
}

#endif  // #ifndef TSAN_GO

static rlim_t getlim(int res) {
  rlimit rlim;
  CHECK_EQ(0, getrlimit(res, &rlim));
  return rlim.rlim_cur;
}

static void setlim(int res, rlim_t lim) {
  // The following magic is to prevent clang from replacing it with memset.
  volatile rlimit rlim;
  rlim.rlim_cur = lim;
  rlim.rlim_max = lim;
  setrlimit(res, (rlimit*)&rlim);
}

const char *InitializePlatform() {
  void *p = 0;
  if (sizeof(p) == 8) {
    // Disable core dumps, dumping of 16TB usually takes a bit long.
    setlim(RLIMIT_CORE, 0);
  }

  // Go maps shadow memory lazily and works fine with limited address space.
  // Unlimited stack is not a problem as well, because the executable
  // is not compiled with -pie.
  if (kCppMode) {
    bool reexec = false;
    // TSan doesn't play well with unlimited stack size (as stack
    // overlaps with shadow memory). If we detect unlimited stack size,
    // we re-exec the program with limited stack size as a best effort.
    if (getlim(RLIMIT_STACK) == (rlim_t)-1) {
      const uptr kMaxStackSize = 32 * 1024 * 1024;
      VReport(1, "Program is run with unlimited stack size, which wouldn't "
                 "work with ThreadSanitizer.\n"
                 "Re-execing with stack size limited to %zd bytes.\n",
              kMaxStackSize);
      SetStackSizeLimitInBytes(kMaxStackSize);
      reexec = true;
    }

    if (getlim(RLIMIT_AS) != (rlim_t)-1) {
      Report("WARNING: Program is run with limited virtual address space,"
             " which wouldn't work with ThreadSanitizer.\n");
      Report("Re-execing with unlimited virtual address space.\n");
      setlim(RLIMIT_AS, -1);
      reexec = true;
    }
    if (reexec)
      ReExec();
  }

#ifndef TSAN_GO
  CheckPIE();
  InitTlsSize();
  InitDataSeg();
#endif
  return GetEnv(kTsanOptionsEnv);
}

bool IsGlobalVar(uptr addr) {
  return g_data_start && addr >= g_data_start && addr < g_data_end;
}

#ifndef TSAN_GO
// Extract file descriptors passed to glibc internal __res_iclose function.
// This is required to properly "close" the fds, because we do not see internal
// closes within glibc. The code is a pure hack.
int ExtractResolvFDs(void *state, int *fds, int nfd) {
  int cnt = 0;
  __res_state *statp = (__res_state*)state;
  for (int i = 0; i < MAXNS && cnt < nfd; i++) {
    if (statp->_u._ext.nsaddrs[i] && statp->_u._ext.nssocks[i] != -1)
      fds[cnt++] = statp->_u._ext.nssocks[i];
  }
  return cnt;
}

// Extract file descriptors passed via UNIX domain sockets.
// This is requried to properly handle "open" of these fds.
// see 'man recvmsg' and 'man 3 cmsg'.
int ExtractRecvmsgFDs(void *msgp, int *fds, int nfd) {
  int res = 0;
  msghdr *msg = (msghdr*)msgp;
  struct cmsghdr *cmsg = CMSG_FIRSTHDR(msg);
  for (; cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {
    if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS)
      continue;
    int n = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(fds[0]);
    for (int i = 0; i < n; i++) {
      fds[res++] = ((int*)CMSG_DATA(cmsg))[i];
      if (res == nfd)
        return res;
    }
  }
  return res;
}
#endif

}  // namespace __tsan

#endif  // SANITIZER_LINUX
<|endoftext|>


<commit_before>/*
    kopetemimetypehandler.cpp - Kopete mime type handlers

    Copyright (c) 2004      by Richard Smith         <kde@metafoo.co.uk>

    Kopete    (c) 2004      by the Kopete developers <kopete-devel@kde.org>

    *************************************************************************
    *                                                                       *
    * 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 of the License, or (at your option) any later version.      *
    *                                                                       *
    *************************************************************************
*/

#include "kopetemimetypehandler.h"
#include "kopeteglobal.h"
#include "kopeteuiglobal.h"

#include <qwidget.h>

#include <kapplication.h>
#include <kdebug.h>
#include <klocale.h>
#include <kio/netaccess.h>
#include <kmimetype.h>
#include <kmessagebox.h>
#include <kstandarddirs.h>
#include <ktar.h>

namespace Kopete
{

namespace
{
	static QHash<QString, Kopete::MimeTypeHandler*> g_mimeHandlers;
	static QHash<QString, Kopete::MimeTypeHandler*> g_protocolHandlers;
}

class MimeTypeHandler::Private
{
public:
	Private( bool carf ) : canAcceptRemoteFiles( carf ) {}
	bool canAcceptRemoteFiles;
	QStringList mimeTypes;
	QStringList protocols;
};

MimeTypeHandler::MimeTypeHandler( bool canAcceptRemoteFiles )
 : d( new Private( canAcceptRemoteFiles ) )
{
}

MimeTypeHandler::~MimeTypeHandler()
{
	for( QStringList::iterator it = d->mimeTypes.begin(); it != d->mimeTypes.end(); ++it )
		g_mimeHandlers.remove( *it );

	for( QStringList::iterator it = d->protocols.begin(); it != d->protocols.end(); ++it )
		g_protocolHandlers.remove( *it );

	delete d;
}

bool MimeTypeHandler::registerAsMimeHandler( const QString &mimeType )
{
	if( g_mimeHandlers[ mimeType ] )
	{
		kWarning(14010) << k_funcinfo << "Warning: Two mime type handlers attempting"
			" to handle " << mimeType << endl;
		return false;
	}

	g_mimeHandlers.insert( mimeType, this );
	d->mimeTypes.append( mimeType );
//	kDebug(14010) << k_funcinfo << "Mime type " << mimeType << " registered" << endl;
	return true;
}

bool MimeTypeHandler::registerAsProtocolHandler( const QString &protocol )
{
	if( g_protocolHandlers[ protocol ] )
	{
		kWarning(14010) << k_funcinfo << "Warning: Two protocol handlers attempting"
			" to handle " << protocol << endl;
		return false;
	}

	g_protocolHandlers.insert( protocol, this );
	d->protocols.append( protocol );
	kDebug(14010) << k_funcinfo << "Mime type " << protocol << " registered" << endl;
	return true;
}

const QStringList MimeTypeHandler::mimeTypes() const
{
	return d->mimeTypes;
}

const QStringList MimeTypeHandler::protocols() const
{
	return d->protocols;
}

bool MimeTypeHandler::canAcceptRemoteFiles() const
{
	return d->canAcceptRemoteFiles;
}

bool MimeTypeHandler::dispatchURL( const KUrl &url )
{
	if( url.isEmpty() )
		return false;

	QString type = KMimeType::findByURL( url )->name();

	MimeTypeHandler *mimeHandler = g_mimeHandlers[ type ];

	if( mimeHandler )
	{
		return dispatchToHandler( url, type, mimeHandler );
	}
	else
	{
		mimeHandler = g_protocolHandlers[ url.protocol() ];

		if( mimeHandler )
		{
			mimeHandler->handleURL( url );
			return true;
		}
		else
		{
			kDebug(14010) << "No mime type handler can handle this URL: " << url.prettyUrl() << endl;
			return false;
		}
	}
}

bool MimeTypeHandler::dispatchToHandler( const KUrl &url, const QString &mimeType, MimeTypeHandler *handler )
{
	if( !handler->canAcceptRemoteFiles() )
	{
		QString file;
		if( !KIO::NetAccess::download( url, file, Kopete::UI::Global::mainWidget() ) )
		{
			QString sorryText;
			if ( url.isLocalFile() )
			{
				sorryText = i18n( "Unable to find the file %1.", url.prettyUrl() );
			}
			else
			{
				sorryText = i18n( "<qt>Unable to download the requested file;
"
				                  "please check that address %1 is correct.</qt>",
				                  url.prettyUrl() );
			}

			KMessageBox::sorry( Kopete::UI::Global::mainWidget(), sorryText );
			return false;
		}

		KUrl dest;
		dest.setPath( file );

		if( !mimeType.isNull() )
			handler->handleURL( mimeType, dest );
		else
			handler->handleURL( dest );

		// for now, local-only handlers have to be synchronous
		KIO::NetAccess::removeTempFile( file );
	}
	else
	{
		if( !mimeType.isNull() )
			handler->handleURL( mimeType, url );
		else
			handler->handleURL( url );
	}

	return true;
}

void MimeTypeHandler::handleURL( const KUrl &url ) const
{
	Q_UNUSED( url );
}

void MimeTypeHandler::handleURL( const QString &mimeType, const KUrl &url ) const
{
	Q_UNUSED( mimeType );
	Q_UNUSED( url );
}

EmoticonMimeTypeHandler::EmoticonMimeTypeHandler()
 : MimeTypeHandler( false )
{
	registerAsMimeHandler( QString::fromLatin1("application/x-kopete-emoticons") );
	registerAsMimeHandler( QString::fromLatin1("application/x-tgz") );
	registerAsMimeHandler( QString::fromLatin1("application/x-tbz") );
}

void EmoticonMimeTypeHandler::handleURL( const QString &, const KUrl &url ) const
{
	Global::installEmoticonTheme( url.path() );
}

} // END namespace Kopete

// vim: set noet ts=4 sts=4 sw=4:
<commit_msg>compile<commit_after>/*
    kopetemimetypehandler.cpp - Kopete mime type handlers

    Copyright (c) 2004      by Richard Smith         <kde@metafoo.co.uk>

    Kopete    (c) 2004      by the Kopete developers <kopete-devel@kde.org>

    *************************************************************************
    *                                                                       *
    * 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 of the License, or (at your option) any later version.      *
    *                                                                       *
    *************************************************************************
*/

#include "kopetemimetypehandler.h"
#include "kopeteglobal.h"
#include "kopeteuiglobal.h"

#include <qwidget.h>

#include <kapplication.h>
#include <kdebug.h>
#include <klocale.h>
#include <kio/netaccess.h>
#include <kmimetype.h>
#include <kmessagebox.h>
#include <kstandarddirs.h>
#include <ktar.h>

namespace Kopete
{

namespace
{
	static QHash<QString, Kopete::MimeTypeHandler*> g_mimeHandlers;
	static QHash<QString, Kopete::MimeTypeHandler*> g_protocolHandlers;
}

class MimeTypeHandler::Private
{
public:
	Private( bool carf ) : canAcceptRemoteFiles( carf ) {}
	bool canAcceptRemoteFiles;
	QStringList mimeTypes;
	QStringList protocols;
};

MimeTypeHandler::MimeTypeHandler( bool canAcceptRemoteFiles )
 : d( new Private( canAcceptRemoteFiles ) )
{
}

MimeTypeHandler::~MimeTypeHandler()
{
	for( QStringList::iterator it = d->mimeTypes.begin(); it != d->mimeTypes.end(); ++it )
		g_mimeHandlers.remove( *it );

	for( QStringList::iterator it = d->protocols.begin(); it != d->protocols.end(); ++it )
		g_protocolHandlers.remove( *it );

	delete d;
}

bool MimeTypeHandler::registerAsMimeHandler( const QString &mimeType )
{
	if( g_mimeHandlers[ mimeType ] )
	{
		kWarning(14010) << k_funcinfo << "Warning: Two mime type handlers attempting"
			" to handle " << mimeType << endl;
		return false;
	}

	g_mimeHandlers.insert( mimeType, this );
	d->mimeTypes.append( mimeType );
//	kDebug(14010) << k_funcinfo << "Mime type " << mimeType << " registered" << endl;
	return true;
}

bool MimeTypeHandler::registerAsProtocolHandler( const QString &protocol )
{
	if( g_protocolHandlers[ protocol ] )
	{
		kWarning(14010) << k_funcinfo << "Warning: Two protocol handlers attempting"
			" to handle " << protocol << endl;
		return false;
	}

	g_protocolHandlers.insert( protocol, this );
	d->protocols.append( protocol );
	kDebug(14010) << k_funcinfo << "Mime type " << protocol << " registered" << endl;
	return true;
}

const QStringList MimeTypeHandler::mimeTypes() const
{
	return d->mimeTypes;
}

const QStringList MimeTypeHandler::protocols() const
{
	return d->protocols;
}

bool MimeTypeHandler::canAcceptRemoteFiles() const
{
	return d->canAcceptRemoteFiles;
}

bool MimeTypeHandler::dispatchURL( const KUrl &url )
{
	if( url.isEmpty() )
		return false;

	QString type = KMimeType::findByUrl( url )->name();

	MimeTypeHandler *mimeHandler = g_mimeHandlers[ type ];

	if( mimeHandler )
	{
		return dispatchToHandler( url, type, mimeHandler );
	}
	else
	{
		mimeHandler = g_protocolHandlers[ url.protocol() ];

		if( mimeHandler )
		{
			mimeHandler->handleURL( url );
			return true;
		}
		else
		{
			kDebug(14010) << "No mime type handler can handle this URL: " << url.prettyUrl() << endl;
			return false;
		}
	}
}

bool MimeTypeHandler::dispatchToHandler( const KUrl &url, const QString &mimeType, MimeTypeHandler *handler )
{
	if( !handler->canAcceptRemoteFiles() )
	{
		QString file;
		if( !KIO::NetAccess::download( url, file, Kopete::UI::Global::mainWidget() ) )
		{
			QString sorryText;
			if ( url.isLocalFile() )
			{
				sorryText = i18n( "Unable to find the file %1.", url.prettyUrl() );
			}
			else
			{
				sorryText = i18n( "<qt>Unable to download the requested file;
"
				                  "please check that address %1 is correct.</qt>",
				                  url.prettyUrl() );
			}

			KMessageBox::sorry( Kopete::UI::Global::mainWidget(), sorryText );
			return false;
		}

		KUrl dest;
		dest.setPath( file );

		if( !mimeType.isNull() )
			handler->handleURL( mimeType, dest );
		else
			handler->handleURL( dest );

		// for now, local-only handlers have to be synchronous
		KIO::NetAccess::removeTempFile( file );
	}
	else
	{
		if( !mimeType.isNull() )
			handler->handleURL( mimeType, url );
		else
			handler->handleURL( url );
	}

	return true;
}

void MimeTypeHandler::handleURL( const KUrl &url ) const
{
	Q_UNUSED( url );
}

void MimeTypeHandler::handleURL( const QString &mimeType, const KUrl &url ) const
{
	Q_UNUSED( mimeType );
	Q_UNUSED( url );
}

EmoticonMimeTypeHandler::EmoticonMimeTypeHandler()
 : MimeTypeHandler( false )
{
	registerAsMimeHandler( QString::fromLatin1("application/x-kopete-emoticons") );
	registerAsMimeHandler( QString::fromLatin1("application/x-tgz") );
	registerAsMimeHandler( QString::fromLatin1("application/x-tbz") );
}

void EmoticonMimeTypeHandler::handleURL( const QString &, const KUrl &url ) const
{
	Global::installEmoticonTheme( url.path() );
}

} // END namespace Kopete

// vim: set noet ts=4 sts=4 sw=4:
<|endoftext|>


<commit_before>/*
    kopetemimetypehandler.cpp - Kopete mime type handlers

    Copyright (c) 2004      by Richard Smith         <kde@metafoo.co.uk>

    Kopete    (c) 2004      by the Kopete developers <kopete-devel@kde.org>

    *************************************************************************
    *                                                                       *
    * 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 of the License, or (at your option) any later version.      *
    *                                                                       *
    *************************************************************************
*/

#include "kopetemimetypehandler.h"
#include "kopeteglobal.h"
#include "kopeteuiglobal.h"

#include <qwidget.h>

#include <kapplication.h>
#include <kdebug.h>
#include <klocale.h>
#include <kio/netaccess.h>
#include <kmimetype.h>
#include <kmessagebox.h>
#include <kprogress.h>
#include <kstandarddirs.h>
#include <ktar.h>

namespace Kopete
{

namespace
{
	static QDict<Kopete::MimeTypeHandler> g_mimeHandlers;
	static QDict<Kopete::MimeTypeHandler> g_protocolHandlers;
}

class MimeTypeHandler::Private
{
public:
	Private( bool carf ) : canAcceptRemoteFiles( carf ) {}
	bool canAcceptRemoteFiles;
	QStringList mimeTypes;
	QStringList protocols;
};

MimeTypeHandler::MimeTypeHandler( bool canAcceptRemoteFiles )
 : d( new Private( canAcceptRemoteFiles ) )
{
}

MimeTypeHandler::~MimeTypeHandler()
{
	for( QStringList::iterator it = d->mimeTypes.begin(); it != d->mimeTypes.end(); ++it )
		g_mimeHandlers.remove( *it );

	for( QStringList::iterator it = d->protocols.begin(); it != d->protocols.end(); ++it )
		g_protocolHandlers.remove( *it );

	delete d;
}

bool MimeTypeHandler::registerAsMimeHandler( const QString &mimeType )
{
	if( g_mimeHandlers[ mimeType ] )
	{
		kdWarning(14010) << k_funcinfo << "Warning: Two mime type handlers attempting"
			" to handle " << mimeType << endl;
		return false;
	}

	g_mimeHandlers.insert( mimeType, this );
	d->mimeTypes.append( mimeType );
	kdDebug(14010) << k_funcinfo << "Mime type " << mimeType << " registered" << endl;
	return true;
}

bool MimeTypeHandler::registerAsProtocolHandler( const QString &protocol )
{
	if( g_protocolHandlers[ protocol ] )
	{
		kdWarning(14010) << k_funcinfo << "Warning: Two protocol handlers attempting"
			" to handle " << protocol << endl;
		return false;
	}

	g_protocolHandlers.insert( protocol, this );
	d->protocols.append( protocol );
	kdDebug(14010) << k_funcinfo << "Mime type " << protocol << " registered" << endl;
	return true;
}

const QStringList MimeTypeHandler::mimeTypes() const
{
	return d->mimeTypes;
}

const QStringList MimeTypeHandler::protocols() const
{
	return d->protocols;
}

bool MimeTypeHandler::canAcceptRemoteFiles() const
{
	return d->canAcceptRemoteFiles;
}

bool MimeTypeHandler::dispatchURL( const KURL &url )
{
	if( url.isEmpty() )
		return false;

	QString type = KMimeType::findByURL( url )->name();

	MimeTypeHandler *mimeHandler = g_mimeHandlers[ type ];

	if( mimeHandler )
	{
		return dispatchToHandler( url, type, mimeHandler );
	}
	else
	{
		mimeHandler = g_protocolHandlers[ url.protocol() ];

		if( mimeHandler )
		{
			mimeHandler->handleURL( url );
		}
		else
		{
			kdDebug(14010) << "No mime type handler can handle this URL: " << url.prettyURL() << endl;
			return false;
		}
	}
}

bool MimeTypeHandler::dispatchToHandler( const KURL &url, const QString &mimeType, MimeTypeHandler *handler )
{
	if( !handler->canAcceptRemoteFiles() )
	{
		QString file;
		#if KDE_IS_VERSION( 3, 1, 90 )
		if( !KIO::NetAccess::download( url, file, Kopete::UI::Global::mainWidget() ) )
		#else
		if( !KIO::NetAccess::download( url, file ) )
		#endif
		{
			QString sorryText;
			if ( url.isLocalFile() )
			{
				sorryText = i18n( "Unable to find the file %1." );
			}
			else
			{
				sorryText = i18n( "<qt>Unable to download the requested file;
"
				                  "please check that address %1 is correct.</qt>" );
			}

			KMessageBox::sorry( Kopete::UI::Global::mainWidget(),
			                    sorryText.arg( url.prettyURL() ) );
			return false;
		}

		KURL dest;
		dest.setPath( file );

		if( !mimeType.isNull() )
			handler->handleURL( mimeType, dest );
		else
			handler->handleURL( dest );

		// for now, local-only handlers have to be synchronous
		KIO::NetAccess::removeTempFile( file );
	}
	else
	{
		if( !mimeType.isNull() )
			handler->handleURL( mimeType, url );
		else
			handler->handleURL( url );
	}

	return true;
}

EmoticonMimeTypeHandler::EmoticonMimeTypeHandler()
 : MimeTypeHandler( false )
{
	registerAsMimeHandler( QString::fromLatin1("application/x-kopete-emoticons") );
	registerAsMimeHandler( QString::fromLatin1("application/x-tgz") );
	registerAsMimeHandler( QString::fromLatin1("application/x-tbz") );
}

void EmoticonMimeTypeHandler::handleURL( const QString &, const KURL &url ) const
{
	Global::installEmoticonTheme( url.path() );
}

} // END namespace Kopete

// vim: set noet ts=4 sts=4 sw=4:
<commit_msg>always return something<commit_after>/*
    kopetemimetypehandler.cpp - Kopete mime type handlers

    Copyright (c) 2004      by Richard Smith         <kde@metafoo.co.uk>

    Kopete    (c) 2004      by the Kopete developers <kopete-devel@kde.org>

    *************************************************************************
    *                                                                       *
    * 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 of the License, or (at your option) any later version.      *
    *                                                                       *
    *************************************************************************
*/

#include "kopetemimetypehandler.h"
#include "kopeteglobal.h"
#include "kopeteuiglobal.h"

#include <qwidget.h>

#include <kapplication.h>
#include <kdebug.h>
#include <klocale.h>
#include <kio/netaccess.h>
#include <kmimetype.h>
#include <kmessagebox.h>
#include <kprogress.h>
#include <kstandarddirs.h>
#include <ktar.h>

namespace Kopete
{

namespace
{
	static QDict<Kopete::MimeTypeHandler> g_mimeHandlers;
	static QDict<Kopete::MimeTypeHandler> g_protocolHandlers;
}

class MimeTypeHandler::Private
{
public:
	Private( bool carf ) : canAcceptRemoteFiles( carf ) {}
	bool canAcceptRemoteFiles;
	QStringList mimeTypes;
	QStringList protocols;
};

MimeTypeHandler::MimeTypeHandler( bool canAcceptRemoteFiles )
 : d( new Private( canAcceptRemoteFiles ) )
{
}

MimeTypeHandler::~MimeTypeHandler()
{
	for( QStringList::iterator it = d->mimeTypes.begin(); it != d->mimeTypes.end(); ++it )
		g_mimeHandlers.remove( *it );

	for( QStringList::iterator it = d->protocols.begin(); it != d->protocols.end(); ++it )
		g_protocolHandlers.remove( *it );

	delete d;
}

bool MimeTypeHandler::registerAsMimeHandler( const QString &mimeType )
{
	if( g_mimeHandlers[ mimeType ] )
	{
		kdWarning(14010) << k_funcinfo << "Warning: Two mime type handlers attempting"
			" to handle " << mimeType << endl;
		return false;
	}

	g_mimeHandlers.insert( mimeType, this );
	d->mimeTypes.append( mimeType );
	kdDebug(14010) << k_funcinfo << "Mime type " << mimeType << " registered" << endl;
	return true;
}

bool MimeTypeHandler::registerAsProtocolHandler( const QString &protocol )
{
	if( g_protocolHandlers[ protocol ] )
	{
		kdWarning(14010) << k_funcinfo << "Warning: Two protocol handlers attempting"
			" to handle " << protocol << endl;
		return false;
	}

	g_protocolHandlers.insert( protocol, this );
	d->protocols.append( protocol );
	kdDebug(14010) << k_funcinfo << "Mime type " << protocol << " registered" << endl;
	return true;
}

const QStringList MimeTypeHandler::mimeTypes() const
{
	return d->mimeTypes;
}

const QStringList MimeTypeHandler::protocols() const
{
	return d->protocols;
}

bool MimeTypeHandler::canAcceptRemoteFiles() const
{
	return d->canAcceptRemoteFiles;
}

bool MimeTypeHandler::dispatchURL( const KURL &url )
{
	if( url.isEmpty() )
		return false;

	QString type = KMimeType::findByURL( url )->name();

	MimeTypeHandler *mimeHandler = g_mimeHandlers[ type ];

	if( mimeHandler )
	{
		return dispatchToHandler( url, type, mimeHandler );
	}
	else
	{
		mimeHandler = g_protocolHandlers[ url.protocol() ];

		if( mimeHandler )
		{
			mimeHandler->handleURL( url );
		}
		else
		{
			kdDebug(14010) << "No mime type handler can handle this URL: " << url.prettyURL() << endl;
		}
	}
	return false;
}

bool MimeTypeHandler::dispatchToHandler( const KURL &url, const QString &mimeType, MimeTypeHandler *handler )
{
	if( !handler->canAcceptRemoteFiles() )
	{
		QString file;
		#if KDE_IS_VERSION( 3, 1, 90 )
		if( !KIO::NetAccess::download( url, file, Kopete::UI::Global::mainWidget() ) )
		#else
		if( !KIO::NetAccess::download( url, file ) )
		#endif
		{
			QString sorryText;
			if ( url.isLocalFile() )
			{
				sorryText = i18n( "Unable to find the file %1." );
			}
			else
			{
				sorryText = i18n( "<qt>Unable to download the requested file;
"
				                  "please check that address %1 is correct.</qt>" );
			}

			KMessageBox::sorry( Kopete::UI::Global::mainWidget(),
			                    sorryText.arg( url.prettyURL() ) );
			return false;
		}

		KURL dest;
		dest.setPath( file );

		if( !mimeType.isNull() )
			handler->handleURL( mimeType, dest );
		else
			handler->handleURL( dest );

		// for now, local-only handlers have to be synchronous
		KIO::NetAccess::removeTempFile( file );
	}
	else
	{
		if( !mimeType.isNull() )
			handler->handleURL( mimeType, url );
		else
			handler->handleURL( url );
	}

	return true;
}

EmoticonMimeTypeHandler::EmoticonMimeTypeHandler()
 : MimeTypeHandler( false )
{
	registerAsMimeHandler( QString::fromLatin1("application/x-kopete-emoticons") );
	registerAsMimeHandler( QString::fromLatin1("application/x-tgz") );
	registerAsMimeHandler( QString::fromLatin1("application/x-tbz") );
}

void EmoticonMimeTypeHandler::handleURL( const QString &, const KURL &url ) const
{
	Global::installEmoticonTheme( url.path() );
}

} // END namespace Kopete

// vim: set noet ts=4 sts=4 sw=4:
<|endoftext|>


<commit_before>/**
 * @file utils/filesystem.hpp
 * @brief Filesystem utility functions
 * @author Paolo D'Apice
 */

#ifndef VIS_UTILS_FILESYSTEM_HPP
#define VIS_UTILS_FILESYSTEM_HPP

#include <boost/filesystem.hpp>
#include <boost/iterator/filter_iterator.hpp>
#include <functional>
#include <string>
#include <vector>

namespace vis {

namespace fs = boost::filesystem;

/// Match image file paths.
struct has_image_extension {
    bool operator()(const fs::path& p) {
        const fs::path ext = p.extension();
        return ext == ".png" || ext == ".jpg";
    }
};

/// Get image files in given directory.
std::vector<fs::path>
getImageFiles(const fs::path& dir) {
    std::vector<fs::path> files;

    fs::directory_iterator it = fs::directory_iterator(dir),
                           end = fs::directory_iterator();

    std::copy(boost::make_filter_iterator<has_image_extension>(it, end),
              boost::make_filter_iterator<has_image_extension>(end, end),
              std::back_inserter(files));

    return files;
}

// TODO unit test for this
void path2string(const std::vector<fs::path>& paths, std::vector<std::string>& names) {
    std::transform(paths.begin(), paths.end(), std::back_inserter(names),
                   std::mem_fun_ref<std::string,fs::path>(&fs::path::string));
}

} /* namespace vis */

#endif /* VIS_UTILS_FILESYSTEM_HPP */

<commit_msg>Removed namespace alias from header file<commit_after>/**
 * @file utils/filesystem.hpp
 * @brief Filesystem utility functions
 * @author Paolo D'Apice
 */

#ifndef VIS_UTILS_FILESYSTEM_HPP
#define VIS_UTILS_FILESYSTEM_HPP

#include <boost/filesystem.hpp>
#include <boost/iterator/filter_iterator.hpp>
#include <functional>
#include <string>
#include <vector>

namespace vis {

/// Match image file paths.
struct has_image_extension {
    bool operator()(const boost::filesystem::path& p) {
        const boost::filesystem::path ext = p.extension();
        return ext == ".png" || ext == ".jpg";
    }
};

/// Get image files in given directory.
std::vector<boost::filesystem::path>
getImageFiles(const boost::filesystem::path& dir) {
    std::vector<boost::filesystem::path> files;

    boost::filesystem::directory_iterator it = boost::filesystem::directory_iterator(dir),
                           end = boost::filesystem::directory_iterator();

    std::copy(boost::make_filter_iterator<has_image_extension>(it, end),
              boost::make_filter_iterator<has_image_extension>(end, end),
              std::back_inserter(files));

    return files;
}

// TODO unit test for this
void path2string(const std::vector<boost::filesystem::path>& paths, std::vector<std::string>& names) {
    std::transform(paths.begin(), paths.end(), std::back_inserter(names),
                   std::mem_fun_ref<std::string,boost::filesystem::path>(&boost::filesystem::path::string));
}

} /* namespace vis */

#endif /* VIS_UTILS_FILESYSTEM_HPP */

<|endoftext|>