<commit_before>/**
 *  @file server.cpp
 *  @author shae, CS5201 Section A
 *  @date Apr 27, 2016
 *  @brief Description:
 *  @details Details:
 */

/************************************************************************/
/*   PROGRAM NAME: server1.c  (works with client.c)                     */
/*                                                                      */
/*   Server creates a socket to listen for the connection from Client   */
/*   When the communication established, Server echoes data from Client */
/*   and writes them back.                                              */
/*                                                                      */
/*   Using socket() to create an endpoint for communication. It         */
/*   returns socket descriptor. Stream socket (SOCK_STREAM) is used here*/
/*   as opposed to a Datagram Socket (SOCK_DGRAM)                       */
/*   Using bind() to bind/assign a name to an unnamed socket.           */
/*   Using listen() to listen for connections on a socket.              */
/*   Using accept() to accept a connection on a socket. It returns      */
/*   the descriptor for the accepted socket.                            */
/*                                                                      */
/*   To run this program, first compile the server_ex.c and run it      */
/*   on a server machine. Then run the client program on another        */
/*   machine.                                                           */
/*                                                                      */
/*   COMPILE:        gcc server1.c -o server1 -lnsl                     */
/*                                                                      */
/************************************************************************/

#include <string.h>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>  /* define socket */
#include <netinet/in.h>  /* define internet socket */
#include <netdb.h>       /* define internet socket */
#include <pthread.h>

#define SERVER_PORT 9993        /* define a server port number */
#define MAX_CLIENT 100

void *input_thread(void *arg);
void *server_thread(void *arg);
void *main_thread(void* arg);
void *client_messenger(void* arg);

pthread_mutex_t stop_lock;
pthread_mutex_t file_descriptor_lock;
bool stop = false;
int sd, ns, k;
struct sockaddr_in server_addr;
struct sockaddr_in client_addr;
unsigned int client_len;
char *host;
int file_descriptor_array[MAX_CLIENT]; /* allocate as many file descriptors
 as the number of clients  */
pthread_t input_handler;
pthread_t client_handler;
pthread_t client_handlers[100];
int counter = 0;

int main()
{

  server_addr =
  { AF_INET, htons( SERVER_PORT)};
  client_addr =
  { AF_INET};
  client_len = sizeof(client_addr);

  counter = 0;

  if (pthread_create(&input_handler, NULL, input_thread, NULL) != 0)
  {
    perror("pthread_create() failure.");
    exit(1);
  }

  /* create a stream socket */
  if ((sd = socket( AF_INET, SOCK_STREAM, 0)) == -1)
  {
    perror("server: socket failed");
    exit(1);
  }

  /* bind the socket to an internet port */
  if (bind(sd, (struct sockaddr*) &server_addr, sizeof(server_addr)) == -1)
  {
    perror("server: bind failed");
    exit(1);
  }

  /*
   if (pthread_create(&client_handler, NULL, server_thread, NULL) != 0)
   {
   perror("pthread_create() failure.");
   exit(1);
   }
   */

  if (listen(sd, 10) == -1)
  {
    perror("server: listen failed");
    exit(1);
  }
  printf("SERVER is listening for clients to establish a connection\n");
  while((ns = accept(sd, (struct sockaddr*) &client_addr, &client_len)) > 0)
  {
    pthread_mutex_lock(&file_descriptor_lock);
    file_descriptor_array[counter] = ns; /* first check for room here though */
    pthread_mutex_unlock(&file_descriptor_lock);
    pthread_create(&client_handlers[counter++], NULL, client_messenger, (void*)&file_descriptor_array[counter]);
    counter++;
  }
  pthread_join(input_handler, NULL);
  pthread_join(client_handler, NULL);
  //pthread_join(input_handler, NULL);
  //pthread_join(client_handler, NULL);
  close(sd);
  unlink((const char*) &server_addr.sin_addr);
  //pthread_exit(&writeThread);
  //pthread_exit(&readThread);

  //close(ns);
  //close(sd);
  //unlink((const char*) &server_addr.sin_addr);

  return (0);
}

void *input_thread(void *arg)
{
  pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);

  /* A simple loop with only puts() would allow a thread to write several
   lines in a row.
   With pthread_yield(), each thread gives another thread a chance before
   it writes its next line */

  while (1)
  {
    //puts((char*) arg);
    char temp[20] = "";
    std::cin >> temp;
    std::cout << "you entered " << std::endl;

    std::cout << temp;
    if (strcmp(temp, "/QUIT") == 0)
    {

      pthread_mutex_lock(&stop_lock);

      stop = true;

      pthread_mutex_unlock(&stop_lock);
      for (int i = 0; i < counter; i++)
      {
        pthread_cancel(client_handlers[i]);
      }
      pthread_exit(0);
    }
    pthread_yield();
  }
}

/*
 void *server_thread(void *arg)
 {
 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,NULL);
 while (!pthread_mutex_trylock(&stop_lock) && !stop)
 {
 //std::cout << (stop ? "TRUE " : "FALSE ") << std::endl;
 pthread_mutex_unlock(&stop_lock);
 /* listen for clients
 if (listen(sd, 4) == -1)
 {
 perror("server: listen failed");
 exit(1);
 }

 printf("SERVER is listening for clients to establish a connection\n");

 if ((ns = accept(sd, (struct sockaddr*) &client_addr, &client_len)) == -1)
 {
 perror("server: accept failed");
 exit(1);
 }

 printf(
 "accept() successful.. a client has connected! waiting for a message\n");

 /* data transfer on connected socket ns
 while ((k = read(ns, buf, sizeof(buf))) != 0 && !stop)
 {
 printf("SERVER RECEIVED: %s\n", buf);
 write(ns, buf, k);
 //write(ns, temp, sizeof(temp));
 }

 }
 }
 */

/*
 void *main_thread(void* arg)
 {
 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,NULL);
 if (listen(sd, 10) == -1)
 {
 perror("server: listen failed");
 exit(1);
 }
 while((ns = accept(sd, (struct sockaddr*) &client_addr, &client_len)) > 0)
 {
 pthread_mutex_lock(&file_descriptor_lock);
 file_descriptor_array[counter++] = ns; /* first check for room here though ///
 pthread_mutex_unlock(&file_descriptor_lock);
 pthread_create(&client_handlers[counter++], NULL, input_thread, (void*)&file_descriptor_array[counter]);
 }
 //pthread_join(input_handler, NULL);
 //pthread_join(client_handler, NULL);
 close(sd);
 unlink((const char*) &server_addr.sin_addr);
 pthread_exit(0);
 }
 */

void *client_messenger(void* arg) /* what does 'bob' do ? */
{
  pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
  printf("Child accept() successful.. a client has connected to child ! waiting for a message\n");
  //this is FD, fd, or file descriptor
  char buf[512];
  int some_fd = *(int*) arg;
  std::cout << some_fd << std::endl;
  char host_name[100];
  gethostname(host_name, 100);
  char client_name[512];
  char message_buffer[100 + 512];
  char server_message[100];
  std::cout << "hello " << std::endl;
  while ((k = read(some_fd, buf, sizeof(buf))) != 0)
  {
    std::cout << "hello" << std::endl;
    strcpy(message_buffer, "HELLO ");
    strcpy(client_name, buf);
    strncat(message_buffer, client_name, 512);
    printf("GIVEN MESSAGE: %s\n", buf);
    for (int i = 0; i < counter; i++)
    {
      write(file_descriptor_array[i], message_buffer, k);
    }
    break;
  }
  while ((k = read(some_fd, buf, sizeof(buf))) != 0 && !stop)
  {
    printf("SERVER RECEIVED: %s\n", buf);
    strcpy(message_buffer, client_name);
    strncat(message_buffer, " says:", 6);

    for (int i = 0; i < counter; i++)
    {
      write(file_descriptor_array[i], message_buffer, k);
    }
    pthread_mutex_unlock(&file_descriptor_lock);
  }

  pthread_mutex_lock(&file_descriptor_lock);
  int i = 0;
  while ((file_descriptor_array[i] != some_fd))
  {
    i++;
  }
  counter--;
  for (int j = i; j < counter; j++)
  {
    file_descriptor_array[j] = file_descriptor_array[j - 1];
  }
  pthread_mutex_unlock(&file_descriptor_lock);
  close(some_fd);
  pthread_exit(0);

}
<commit_msg>Server Almost Donzo<commit_after>/**
 *  @file server.cpp
 *  @author shae, CS5201 Section A
 *  @date Apr 27, 2016
 *  @brief Description:
 *  @details Details:
 */

/************************************************************************/
/*   PROGRAM NAME: server1.c  (works with client.c)                     */
/*                                                                      */
/*   Server creates a socket to listen for the connection from Client   */
/*   When the communication established, Server echoes data from Client */
/*   and writes them back.                                              */
/*                                                                      */
/*   Using socket() to create an endpoint for communication. It         */
/*   returns socket descriptor. Stream socket (SOCK_STREAM) is used here*/
/*   as opposed to a Datagram Socket (SOCK_DGRAM)                       */
/*   Using bind() to bind/assign a name to an unnamed socket.           */
/*   Using listen() to listen for connections on a socket.              */
/*   Using accept() to accept a connection on a socket. It returns      */
/*   the descriptor for the accepted socket.                            */
/*                                                                      */
/*   To run this program, first compile the server_ex.c and run it      */
/*   on a server machine. Then run the client program on another        */
/*   machine.                                                           */
/*                                                                      */
/*   COMPILE:        gcc server1.c -o server1 -lnsl                     */
/*                                                                      */
/************************************************************************/

#include <string.h>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>  /* define socket */
#include <netinet/in.h>  /* define internet socket */
#include <netdb.h>       /* define internet socket */
#include <pthread.h>
#include <signal.h>

#define SERVER_PORT 9993        /* define a server port number */
#define MAX_CLIENT 100

void *input_thread(void *arg);
void *server_thread(void *arg);
void *main_thread(void* arg);
void *client_messenger(void* arg);
void cntrlc_signal_handle(int signal);

pthread_mutex_t stop_lock;
pthread_mutex_t file_descriptor_lock;
bool stop = false;
int sd, ns, k;
struct sockaddr_in server_addr;
struct sockaddr_in client_addr;
unsigned int client_len;
char *host;
int file_descriptor_array[MAX_CLIENT]; /* allocate as many file descriptors
 as the number of clients  */
pthread_t input_handler;
pthread_t client_handler;
pthread_t client_handlers[100];
int counter;

int main()
{
  signal(SIGINT, cntrlc_signal_handle);
  server_addr =
  { AF_INET, htons( SERVER_PORT)};
  client_addr =
  { AF_INET};
  client_len = sizeof(client_addr);

  counter = 0;

  if (pthread_create(&input_handler, NULL, input_thread, NULL) != 0)
  {
    perror("pthread_create() failure.");
    exit(1);
  }

  /* create a stream socket */
  if ((sd = socket( AF_INET, SOCK_STREAM, 0)) == -1)
  {
    perror("server: socket failed");
    exit(1);
  }
  int enable = 1;
  if (setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) < 0)
  {
    perror("setsockopt(SO_REUSEADDR) failed");
  }

  /* bind the socket to an internet port */
  if (bind(sd, (struct sockaddr*) &server_addr, sizeof(server_addr)) == -1)
  {
    perror("server: bind failed");
    exit(1);
  }

  /*
   if (pthread_create(&client_handler, NULL, server_thread, NULL) != 0)
   {
   perror("pthread_create() failure.");
   exit(1);
   }
   */

  if (listen(sd, 10) == -1)
  {
    perror("server: listen failed");
    exit(1);
  }
  printf("SERVER is listening for clients to establish a connection\n");
  while (((ns = accept(sd, (struct sockaddr*) &client_addr, &client_len)) > 0)
      && !stop)
  {
    pthread_mutex_lock(&file_descriptor_lock);
    if (counter < 100)
    {
      file_descriptor_array[counter] = ns; /* first check for room here though */
      pthread_create(&client_handlers[counter], NULL, client_messenger,
          (void*) &file_descriptor_array[counter]);
      pthread_mutex_unlock(&file_descriptor_lock);
      counter++;
    }
    else
    {
      std::cerr << "Error too many threads" << std::endl;
    }
  }
  //std::cout << "Why are you ending?" << std::endl;
  //pthread_join(input_handler, NULL);
  //pthread_join(client_handler, NULL);
  //pthread_join(input_handler, NULL);
  //pthread_join(client_handler, NULL);
  close(sd);
  unlink((const char*) &server_addr.sin_addr);
  //pthread_exit(&writeThread);
  //pthread_exit(&readThread);

  //close(ns);
  //close(sd);
  //unlink((const char*) &server_addr.sin_addr);

  return (0);
}

void cntrlc_signal_handle(int signal)
{
  std::cout << "\nCNTRLC detected" << std::endl;
  char message_buffer[512] = "ADVISIO: EL SERVIDOR SE APAGARÀ EN 10 SEGUNDOS\n";
  char quit_msg[32] = "/quit";
  for (int i = 0; i < counter; i++)
  {
    //std::cout << "i " << i << std::endl;
    //client_handlers[i];
    write(file_descriptor_array[i], message_buffer, sizeof(message_buffer));
    //std::cout << "i " << i << std::endl;
  }
  for (int i = 0; i < counter; i++)
  {
    std::cout << "sending qm" << std::endl;
    write(file_descriptor_array[i], quit_msg, sizeof(quit_msg));
  }
  sleep(10);
  pthread_mutex_lock(&stop_lock);
  stop = true;
  pthread_mutex_unlock(&stop_lock);
  //std::cout << "canceling done" << std::endl;
  for (int i = 0; i < counter; i++)
  {
    //std::cout << "canceling i " << i << std::endl;
    //std::cout << "i " << i << std::endl;
    pthread_cancel(client_handlers[i]);
    //std::cout << "i " << i << std::endl;
  }
  //std::cout << "canceling done" << std::endl;
  pthread_cancel(input_handler);
  close(sd);
  unlink((const char*) &server_addr.sin_addr);
  //pthread_yield();
}

void *input_thread(void *arg)
{
  pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);

  /* A simple loop with only puts() would allow a thread to write several
   lines in a row.
   With pthread_yield(), each thread gives another thread a chance before
   it writes its next line */

  while (1)
  {

    //puts((char*) arg);
    char temp[20] = "";
    std::cin >> temp;
    std::cout << "you entered " << std::endl;

    std::cout << temp;
    if (strcmp(temp, "/QUIT") == 0)
    {

      pthread_mutex_lock(&stop_lock);

      stop = true;

      pthread_mutex_unlock(&stop_lock);

      char message_buffer[512] = "/quit";
      pthread_mutex_lock(&file_descriptor_lock);
      for (int i = 0; i < counter; i++)
      {
        write(file_descriptor_array[i], message_buffer, sizeof(message_buffer));
      }
      pthread_mutex_unlock(&file_descriptor_lock);

      for (int i = 0; i < counter; i++)
      {
        std::cout << "canceling i " << i << std::endl;
        //std::cout << "i " << i << std::endl;
        pthread_cancel(client_handlers[i]);
        //std::cout << "i " << i << std::endl;
      }
      pthread_exit(0);

    }
    pthread_yield();
  }
}

void *client_messenger(void* arg) /* what does 'bob' do ? */
{
  pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
  printf(
      "Child accept() successful.. a client has connected to child ! waiting for a message\n");
  //this is FD, fd, or file descriptor
  char buf[512];
  int some_fd = *(int*) arg;
  //std::cout << some_fd << std::endl;
  char host_name[100];
  gethostname(host_name, 100);
  char client_name[512];
  char message_buffer[100 + 512];
  char server_message[100];

  while ((k = read(some_fd, buf, sizeof(buf))) != 0)
  {
    strcpy(message_buffer, "Hello User ");
    strcpy(client_name, buf);
    strncat(message_buffer, client_name, 512);
    strncat(message_buffer, "\n", 3);
    //printf("GIVEN MESSAGE: %s\n", buf);

    pthread_mutex_lock(&file_descriptor_lock);
    for (int i = 0; i < counter; i++)
    {
      write(file_descriptor_array[i], message_buffer, sizeof(message_buffer));
    }
    pthread_mutex_unlock(&file_descriptor_lock);
    break;
  }
  while ((k = read(some_fd, buf, sizeof(buf))) != 0 && !stop)
  {
    bzero(message_buffer, 512 + 100);
    printf("SERVER RECEIVED: %s\n", buf);
    if (strcmp(buf, "/quit") == 0)
    {
      break;
    }

    strcpy(message_buffer, ">> ");
    strncat(message_buffer, client_name, sizeof(client_name));
    strncat(message_buffer, ": ", 8);
    strncat(message_buffer, buf, 512);
    strncat(message_buffer, "\n", 3);
    //std::cout << message_buffer << std::endl;
    pthread_mutex_lock(&file_descriptor_lock);
    //std::cout << "done messaging 1" << std::endl;
    for (int i = 0; i < counter; i++)
    {
      if (file_descriptor_array[i] != some_fd)
      {
        std::cout << "Messaging user i = " << i << std::endl;
        write(file_descriptor_array[i], message_buffer, sizeof(message_buffer));
      }
    }
    //std::cout << "done messaging 3" << std::endl;
    pthread_mutex_unlock(&file_descriptor_lock);
    pthread_yield();
  }

  pthread_mutex_lock(&file_descriptor_lock);
  bzero(message_buffer, 512 + 100);
  strcpy(message_buffer, "User ");
  strncat(message_buffer, client_name, sizeof(client_name));
  strncat(message_buffer, " has disconnected.", 24);
  for (int i = 0; i < counter; i++)
  {
    if (file_descriptor_array[i] != some_fd)
    {
      //std::cout << "done messaging 2" << std::endl;
      write(file_descriptor_array[i], message_buffer, sizeof(message_buffer));
    }
  }
  int i = 0;
  while ((file_descriptor_array[i] != some_fd))
  {
    i++;
  }
  counter--;
  for (int j = i; j < counter; j++)
  {
    file_descriptor_array[j] = file_descriptor_array[j - 1];
  }
  pthread_mutex_unlock(&file_descriptor_lock);
  close(some_fd);
  std::cout << "EXITING THREAD" << std::endl;
  pthread_exit(0);
}
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#include "sal/config.h"

#include <cstring>

#include "sal/types.h"
#include "typelib/typeclass.h"
#include "typelib/typedescription.h"

#include "abi.hxx"
#include "callvirtualmethod.hxx"

// The call instruction within the asm block of callVirtualMethod may throw
// exceptions.  At least GCC 4.7.0 with -O0 would create (unnecessary)
// .gcc_exception_table call-site table entries around all other calls in this
// function that can throw, leading to std::terminate if the asm call throws an
// exception and the unwinding C++ personality routine finds the unexpected hole
// in the .gcc_exception_table.  Therefore, make sure this function explicitly
// only calls nothrow-functions (so GCC 4.7.0 with -O0 happens to not create a
// .gcc_exception_table section at all for this function).  For some reason,
// this also needs to be in a source file of its own.
//
// Also, this file should be compiled with -fnon-call-exceptions, and ideally
// there would be a way to tell the compiler that the asm block contains calls
// to functions that can potentially throw; see the mail thread starting at
// <http://gcc.gnu.org/ml/gcc/2012-03/msg00454.html> "C++: Letting compiler know
// asm block can call function that can throw?"

void CPPU_CURRENT_NAMESPACE::callVirtualMethod(
    void * pThis, sal_uInt32 nVtableIndex, void * pRegisterReturn,
    typelib_TypeDescriptionReference * pReturnTypeRef, bool bSimpleReturn,
    sal_uInt64 *pStack, sal_uInt32 nStack, sal_uInt64 *pGPR, sal_uInt32 nGPR,
    double * pFPR, sal_uInt32 nFPR)
{
    // Should not happen, but...
    if ( nFPR > x86_64::MAX_SSE_REGS )
        nFPR = x86_64::MAX_SSE_REGS;
    if ( nGPR > x86_64::MAX_GPR_REGS )
        nGPR = x86_64::MAX_GPR_REGS;

    // Get pointer to method
    sal_uInt64 pMethod = *((sal_uInt64 *)pThis);
    pMethod += 8 * nVtableIndex;
    pMethod = *((sal_uInt64 *)pMethod);

    // Load parameters to stack, if necessary
    if ( nStack )
    {
        // 16-bytes aligned
        sal_uInt32 nStackBytes = ( ( nStack + 1 ) >> 1 ) * 16;
        sal_uInt64 *pCallStack = (sal_uInt64 *) __builtin_alloca( nStackBytes );
        std::memcpy( pCallStack, pStack, nStackBytes );
    }

    // Return values
    sal_uInt64 rax;
    sal_uInt64 rdx;
    double xmm0;
    double xmm1;

    asm volatile (

        // Fill the xmm registers
        "movq %6, %%rax\n\t"

        "movsd   (%%rax), %%xmm0\n\t"
        "movsd  8(%%rax), %%xmm1\n\t"
        "movsd 16(%%rax), %%xmm2\n\t"
        "movsd 24(%%rax), %%xmm3\n\t"
        "movsd 32(%%rax), %%xmm4\n\t"
        "movsd 40(%%rax), %%xmm5\n\t"
        "movsd 48(%%rax), %%xmm6\n\t"
        "movsd 56(%%rax), %%xmm7\n\t"

        // Fill the general purpose registers
        "movq %5, %%rax\n\t"

        "movq    (%%rax), %%rdi\n\t"
        "movq   8(%%rax), %%rsi\n\t"
        "movq  16(%%rax), %%rdx\n\t"
        "movq  24(%%rax), %%rcx\n\t"
        "movq  32(%%rax), %%r8\n\t"
        "movq  40(%%rax), %%r9\n\t"

        // Perform the call
        "movq %4, %%r11\n\t"
        "movq %7, %%rax\n\t"
        "call *%%r11\n\t"

        // Fill the return values
        "movq   %%rax, %0\n\t"
        "movq   %%rdx, %1\n\t"
        "movsd %%xmm0, %2\n\t"
        "movsd %%xmm1, %3\n\t"
        : "=m" ( rax ), "=m" ( rdx ), "=m" ( xmm0 ), "=m" ( xmm1 )
        : "m" ( pMethod ), "m" ( pGPR ), "m" ( pFPR ), "m" ( nFPR )
        : "rax", "rdi", "rsi", "rdx", "rcx", "r8", "r9", "r11"
    );

    switch (pReturnTypeRef->eTypeClass)
    {
    case typelib_TypeClass_HYPER:
    case typelib_TypeClass_UNSIGNED_HYPER:
        *reinterpret_cast<sal_uInt64 *>( pRegisterReturn ) = rax;
        break;
    case typelib_TypeClass_LONG:
    case typelib_TypeClass_UNSIGNED_LONG:
    case typelib_TypeClass_ENUM:
        *reinterpret_cast<sal_uInt32 *>( pRegisterReturn ) = *reinterpret_cast<sal_uInt32*>( &rax );
        break;
    case typelib_TypeClass_CHAR:
    case typelib_TypeClass_SHORT:
    case typelib_TypeClass_UNSIGNED_SHORT:
        *reinterpret_cast<sal_uInt16 *>( pRegisterReturn ) = *reinterpret_cast<sal_uInt16*>( &rax );
        break;
    case typelib_TypeClass_BOOLEAN:
    case typelib_TypeClass_BYTE:
        *reinterpret_cast<sal_uInt8 *>( pRegisterReturn ) = *reinterpret_cast<sal_uInt8*>( &rax );
        break;
    case typelib_TypeClass_FLOAT:
    case typelib_TypeClass_DOUBLE:
        *reinterpret_cast<double *>( pRegisterReturn ) = xmm0;
        break;
    default:
        {
            sal_Int32 const nRetSize = pReturnTypeRef->pType->nSize;
            if (bSimpleReturn && nRetSize <= 16 && nRetSize > 0)
            {
                sal_uInt64 longs[2];
                longs[0] = rax;
                longs[1] = rdx;

                double doubles[2];
                doubles[0] = xmm0;
                doubles[1] = xmm1;
                x86_64::fill_struct( pReturnTypeRef, &longs[0], &doubles[0], pRegisterReturn);
            }
            break;
        }
    }
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>Mark all registered as clobbered that are not saved across call<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#include "sal/config.h"

#include <cstring>

#include "sal/types.h"
#include "typelib/typeclass.h"
#include "typelib/typedescription.h"

#include "abi.hxx"
#include "callvirtualmethod.hxx"

// The call instruction within the asm block of callVirtualMethod may throw
// exceptions.  At least GCC 4.7.0 with -O0 would create (unnecessary)
// .gcc_exception_table call-site table entries around all other calls in this
// function that can throw, leading to std::terminate if the asm call throws an
// exception and the unwinding C++ personality routine finds the unexpected hole
// in the .gcc_exception_table.  Therefore, make sure this function explicitly
// only calls nothrow-functions (so GCC 4.7.0 with -O0 happens to not create a
// .gcc_exception_table section at all for this function).  For some reason,
// this also needs to be in a source file of its own.
//
// Also, this file should be compiled with -fnon-call-exceptions, and ideally
// there would be a way to tell the compiler that the asm block contains calls
// to functions that can potentially throw; see the mail thread starting at
// <http://gcc.gnu.org/ml/gcc/2012-03/msg00454.html> "C++: Letting compiler know
// asm block can call function that can throw?"

void CPPU_CURRENT_NAMESPACE::callVirtualMethod(
    void * pThis, sal_uInt32 nVtableIndex, void * pRegisterReturn,
    typelib_TypeDescriptionReference * pReturnTypeRef, bool bSimpleReturn,
    sal_uInt64 *pStack, sal_uInt32 nStack, sal_uInt64 *pGPR, sal_uInt32 nGPR,
    double * pFPR, sal_uInt32 nFPR)
{
    // Should not happen, but...
    if ( nFPR > x86_64::MAX_SSE_REGS )
        nFPR = x86_64::MAX_SSE_REGS;
    if ( nGPR > x86_64::MAX_GPR_REGS )
        nGPR = x86_64::MAX_GPR_REGS;

    // Get pointer to method
    sal_uInt64 pMethod = *((sal_uInt64 *)pThis);
    pMethod += 8 * nVtableIndex;
    pMethod = *((sal_uInt64 *)pMethod);

    // Load parameters to stack, if necessary
    if ( nStack )
    {
        // 16-bytes aligned
        sal_uInt32 nStackBytes = ( ( nStack + 1 ) >> 1 ) * 16;
        sal_uInt64 *pCallStack = (sal_uInt64 *) __builtin_alloca( nStackBytes );
        std::memcpy( pCallStack, pStack, nStackBytes );
    }

    // Return values
    sal_uInt64 rax;
    sal_uInt64 rdx;
    double xmm0;
    double xmm1;

    asm volatile (

        // Fill the xmm registers
        "movq %6, %%rax\n\t"

        "movsd   (%%rax), %%xmm0\n\t"
        "movsd  8(%%rax), %%xmm1\n\t"
        "movsd 16(%%rax), %%xmm2\n\t"
        "movsd 24(%%rax), %%xmm3\n\t"
        "movsd 32(%%rax), %%xmm4\n\t"
        "movsd 40(%%rax), %%xmm5\n\t"
        "movsd 48(%%rax), %%xmm6\n\t"
        "movsd 56(%%rax), %%xmm7\n\t"

        // Fill the general purpose registers
        "movq %5, %%rax\n\t"

        "movq    (%%rax), %%rdi\n\t"
        "movq   8(%%rax), %%rsi\n\t"
        "movq  16(%%rax), %%rdx\n\t"
        "movq  24(%%rax), %%rcx\n\t"
        "movq  32(%%rax), %%r8\n\t"
        "movq  40(%%rax), %%r9\n\t"

        // Perform the call
        "movq %4, %%r11\n\t"
        "movq %7, %%rax\n\t"
        "call *%%r11\n\t"

        // Fill the return values
        "movq   %%rax, %0\n\t"
        "movq   %%rdx, %1\n\t"
        "movsd %%xmm0, %2\n\t"
        "movsd %%xmm1, %3\n\t"
        : "=m" ( rax ), "=m" ( rdx ), "=m" ( xmm0 ), "=m" ( xmm1 )
        : "m" ( pMethod ), "m" ( pGPR ), "m" ( pFPR ), "m" ( nFPR )
        : "rax", "rdi", "rsi", "rdx", "rcx", "r8", "r9", "r10", "r11",
          "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7",
          "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15"
    );

    switch (pReturnTypeRef->eTypeClass)
    {
    case typelib_TypeClass_HYPER:
    case typelib_TypeClass_UNSIGNED_HYPER:
        *reinterpret_cast<sal_uInt64 *>( pRegisterReturn ) = rax;
        break;
    case typelib_TypeClass_LONG:
    case typelib_TypeClass_UNSIGNED_LONG:
    case typelib_TypeClass_ENUM:
        *reinterpret_cast<sal_uInt32 *>( pRegisterReturn ) = *reinterpret_cast<sal_uInt32*>( &rax );
        break;
    case typelib_TypeClass_CHAR:
    case typelib_TypeClass_SHORT:
    case typelib_TypeClass_UNSIGNED_SHORT:
        *reinterpret_cast<sal_uInt16 *>( pRegisterReturn ) = *reinterpret_cast<sal_uInt16*>( &rax );
        break;
    case typelib_TypeClass_BOOLEAN:
    case typelib_TypeClass_BYTE:
        *reinterpret_cast<sal_uInt8 *>( pRegisterReturn ) = *reinterpret_cast<sal_uInt8*>( &rax );
        break;
    case typelib_TypeClass_FLOAT:
    case typelib_TypeClass_DOUBLE:
        *reinterpret_cast<double *>( pRegisterReturn ) = xmm0;
        break;
    default:
        {
            sal_Int32 const nRetSize = pReturnTypeRef->pType->nSize;
            if (bSimpleReturn && nRetSize <= 16 && nRetSize > 0)
            {
                sal_uInt64 longs[2];
                longs[0] = rax;
                longs[1] = rdx;

                double doubles[2];
                doubles[0] = xmm0;
                doubles[1] = xmm1;
                x86_64::fill_struct( pReturnTypeRef, &longs[0], &doubles[0], pRegisterReturn);
            }
            break;
        }
    }
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>


<commit_before>// Copyright 2014 PDFium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

#include "xfa/fgas/crt/fgas_memory.h"

#define MEMORY_TOOL_REPLACES_ALLOCATOR  // Temporary, for CF testing.

#include <algorithm>

#ifdef MEMORY_TOOL_REPLACES_ALLOCATOR

namespace {

class CFX_DefStore : public IFX_MemoryAllocator, public CFX_Target {
 public:
  CFX_DefStore() {}
  ~CFX_DefStore() override {}
  void* Alloc(size_t size) override { return FX_Alloc(uint8_t, size); }
  void Free(void* pBlock) override { FX_Free(pBlock); }
};

}  // namespace

IFX_MemoryAllocator* IFX_MemoryAllocator::Create(FX_ALLOCTYPE eType,
                                                 size_t chunkSize,
                                                 size_t blockSize) {
  return new CFX_DefStore();
}

#else  // MEMORY_TOOL_REPLACES_ALLOCATOR

namespace {

struct FX_STATICSTORECHUNK {
  FX_STATICSTORECHUNK* pNextChunk;
  size_t iChunkSize;
  size_t iFreeSize;
};

class CFX_StaticStore : public IFX_MemoryAllocator, public CFX_Target {
 public:
  CFX_StaticStore(size_t iDefChunkSize = 4096);
  ~CFX_StaticStore() override;
  void* Alloc(size_t size) override;
  void Free(void* pBlock) override {}

 protected:
  size_t m_iAllocatedSize;
  size_t m_iDefChunkSize;
  FX_STATICSTORECHUNK* m_pChunk;
  FX_STATICSTORECHUNK* m_pLastChunk;
  FX_STATICSTORECHUNK* AllocChunk(size_t size);
  FX_STATICSTORECHUNK* FindChunk(size_t size);
};

struct FX_FIXEDSTORECHUNK {
  uint8_t* FirstFlag() { return reinterpret_cast<uint8_t*>(this + 1); }
  uint8_t* FirstBlock() { return FirstFlag() + iChunkSize; }

  FX_FIXEDSTORECHUNK* pNextChunk;
  size_t iChunkSize;
  size_t iFreeNum;
};

class CFX_FixedStore : public IFX_MemoryAllocator, public CFX_Target {
 public:
  CFX_FixedStore(size_t iBlockSize, size_t iBlockNumsInChunk);
  ~CFX_FixedStore() override;
  void* Alloc(size_t size) override;
  void Free(void* pBlock) override;

 protected:
  FX_FIXEDSTORECHUNK* AllocChunk();

  size_t m_iBlockSize;
  size_t m_iDefChunkSize;
  FX_FIXEDSTORECHUNK* m_pChunk;
};

}  // namespace

#define FX_4BYTEALIGN(size) (((size) + 3) & ~3)

IFX_MemoryAllocator* IFX_MemoryAllocator::Create(FX_ALLOCTYPE eType,
                                                 size_t chunkSize,
                                                 size_t blockSize) {
  switch (eType) {
    case FX_ALLOCTYPE_Static:
      return new CFX_StaticStore(chunkSize);
    case FX_ALLOCTYPE_Fixed:
      return new CFX_FixedStore(blockSize, chunkSize);
    default:
      ASSERT(0);
      return nullptr;
  }
}

CFX_StaticStore::CFX_StaticStore(size_t iDefChunkSize)
    : m_iAllocatedSize(0),
      m_iDefChunkSize(iDefChunkSize),
      m_pChunk(nullptr),
      m_pLastChunk(nullptr) {
  ASSERT(m_iDefChunkSize != 0);
}
CFX_StaticStore::~CFX_StaticStore() {
  FX_STATICSTORECHUNK* pChunk = m_pChunk;
  while (pChunk) {
    FX_STATICSTORECHUNK* pNext = pChunk->pNextChunk;
    FX_Free(pChunk);
    pChunk = pNext;
  }
}
FX_STATICSTORECHUNK* CFX_StaticStore::AllocChunk(size_t size) {
  ASSERT(size != 0);
  FX_STATICSTORECHUNK* pChunk = (FX_STATICSTORECHUNK*)FX_Alloc(
      uint8_t, sizeof(FX_STATICSTORECHUNK) + size);
  pChunk->iChunkSize = size;
  pChunk->iFreeSize = size;
  pChunk->pNextChunk = nullptr;
  if (!m_pLastChunk) {
    m_pChunk = pChunk;
  } else {
    m_pLastChunk->pNextChunk = pChunk;
  }
  m_pLastChunk = pChunk;
  return pChunk;
}
FX_STATICSTORECHUNK* CFX_StaticStore::FindChunk(size_t size) {
  ASSERT(size != 0);
  if (!m_pLastChunk || m_pLastChunk->iFreeSize < size) {
    return AllocChunk(std::max(m_iDefChunkSize, size));
  }
  return m_pLastChunk;
}
void* CFX_StaticStore::Alloc(size_t size) {
  size = FX_4BYTEALIGN(size);
  ASSERT(size != 0);
  FX_STATICSTORECHUNK* pChunk = FindChunk(size);
  ASSERT(pChunk->iFreeSize >= size);
  uint8_t* p = (uint8_t*)pChunk;
  p += sizeof(FX_STATICSTORECHUNK) + pChunk->iChunkSize - pChunk->iFreeSize;
  pChunk->iFreeSize -= size;
  m_iAllocatedSize += size;
  return p;
}
size_t CFX_StaticStore::SetDefChunkSize(size_t size) {
  ASSERT(size != 0);
  size_t v = m_iDefChunkSize;
  m_iDefChunkSize = size;
  return v;
}
CFX_FixedStore::CFX_FixedStore(size_t iBlockSize, size_t iBlockNumsInChunk)
    : m_iBlockSize(FX_4BYTEALIGN(iBlockSize)),
      m_iDefChunkSize(FX_4BYTEALIGN(iBlockNumsInChunk)),
      m_pChunk(nullptr) {
  ASSERT(m_iBlockSize != 0 && m_iDefChunkSize != 0);
}
CFX_FixedStore::~CFX_FixedStore() {
  FX_FIXEDSTORECHUNK* pChunk = m_pChunk;
  while (pChunk) {
    FX_FIXEDSTORECHUNK* pNext = pChunk->pNextChunk;
    FX_Free(pChunk);
    pChunk = pNext;
  }
}
FX_FIXEDSTORECHUNK* CFX_FixedStore::AllocChunk() {
  int32_t iTotalSize = sizeof(FX_FIXEDSTORECHUNK) + m_iDefChunkSize +
                       m_iBlockSize * m_iDefChunkSize;
  FX_FIXEDSTORECHUNK* pChunk =
      (FX_FIXEDSTORECHUNK*)FX_Alloc(uint8_t, iTotalSize);
  if (!pChunk)
    return nullptr;

  FXSYS_memset(pChunk->FirstFlag(), 0, m_iDefChunkSize);
  pChunk->pNextChunk = m_pChunk;
  pChunk->iChunkSize = m_iDefChunkSize;
  pChunk->iFreeNum = m_iDefChunkSize;
  m_pChunk = pChunk;
  return pChunk;
}
void* CFX_FixedStore::Alloc(size_t size) {
  if (size > m_iBlockSize) {
    return nullptr;
  }
  FX_FIXEDSTORECHUNK* pChunk = m_pChunk;
  while (pChunk) {
    if (pChunk->iFreeNum > 0) {
      break;
    }
    pChunk = pChunk->pNextChunk;
  }
  if (!pChunk) {
    pChunk = AllocChunk();
  }
  uint8_t* pFlags = pChunk->FirstFlag();
  size_t i = 0;
  for (; i < pChunk->iChunkSize; i++)
    if (pFlags[i] == 0) {
      break;
    }
  ASSERT(i < pChunk->iChunkSize);
  pFlags[i] = 1;
  pChunk->iFreeNum--;
  return pChunk->FirstBlock() + i * m_iBlockSize;
}
void CFX_FixedStore::Free(void* pBlock) {
  FX_FIXEDSTORECHUNK* pPrior = nullptr;
  FX_FIXEDSTORECHUNK* pChunk = m_pChunk;
  uint8_t* pStart = nullptr;
  uint8_t* pEnd;
  while (pChunk) {
    pStart = pChunk->FirstBlock();
    if (pBlock >= pStart) {
      pEnd = pStart + m_iBlockSize * pChunk->iChunkSize;
      if (pBlock < pEnd) {
        break;
      }
    }
    pPrior = pChunk, pChunk = pChunk->pNextChunk;
  }
  ASSERT(pChunk);
  size_t iPos = ((uint8_t*)pBlock - pStart) / m_iBlockSize;
  ASSERT(iPos < pChunk->iChunkSize);
  uint8_t* pFlags = pChunk->FirstFlag();
  if (pFlags[iPos] == 0) {
    return;
  }
  pFlags[iPos] = 0;
  pChunk->iFreeNum++;
  if (pChunk->iFreeNum == pChunk->iChunkSize) {
    if (!pPrior) {
      m_pChunk = pChunk->pNextChunk;
    } else {
      pPrior->pNextChunk = pChunk->pNextChunk;
    }
    FX_Free(pChunk);
  }
}
size_t CFX_FixedStore::SetDefChunkSize(size_t iChunkSize) {
  ASSERT(iChunkSize != 0);
  size_t v = m_iDefChunkSize;
  m_iDefChunkSize = FX_4BYTEALIGN(iChunkSize);
  return v;
}

#endif  // MEMORY_TOOL_REPLACES_ALLOCATOR
<commit_msg>Only set memory tool define if not set.<commit_after>// Copyright 2014 PDFium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

#include "xfa/fgas/crt/fgas_memory.h"

#ifndef MEMORY_TOOL_REPLACES_ALLOCATOR
#define MEMORY_TOOL_REPLACES_ALLOCATOR  // Temporary, for CF testing.
#endif

#include <algorithm>

#ifdef MEMORY_TOOL_REPLACES_ALLOCATOR

namespace {

class CFX_DefStore : public IFX_MemoryAllocator, public CFX_Target {
 public:
  CFX_DefStore() {}
  ~CFX_DefStore() override {}
  void* Alloc(size_t size) override { return FX_Alloc(uint8_t, size); }
  void Free(void* pBlock) override { FX_Free(pBlock); }
};

}  // namespace

IFX_MemoryAllocator* IFX_MemoryAllocator::Create(FX_ALLOCTYPE eType,
                                                 size_t chunkSize,
                                                 size_t blockSize) {
  return new CFX_DefStore();
}

#else  // MEMORY_TOOL_REPLACES_ALLOCATOR

namespace {

struct FX_STATICSTORECHUNK {
  FX_STATICSTORECHUNK* pNextChunk;
  size_t iChunkSize;
  size_t iFreeSize;
};

class CFX_StaticStore : public IFX_MemoryAllocator, public CFX_Target {
 public:
  CFX_StaticStore(size_t iDefChunkSize = 4096);
  ~CFX_StaticStore() override;
  void* Alloc(size_t size) override;
  void Free(void* pBlock) override {}

 protected:
  size_t m_iAllocatedSize;
  size_t m_iDefChunkSize;
  FX_STATICSTORECHUNK* m_pChunk;
  FX_STATICSTORECHUNK* m_pLastChunk;
  FX_STATICSTORECHUNK* AllocChunk(size_t size);
  FX_STATICSTORECHUNK* FindChunk(size_t size);
};

struct FX_FIXEDSTORECHUNK {
  uint8_t* FirstFlag() { return reinterpret_cast<uint8_t*>(this + 1); }
  uint8_t* FirstBlock() { return FirstFlag() + iChunkSize; }

  FX_FIXEDSTORECHUNK* pNextChunk;
  size_t iChunkSize;
  size_t iFreeNum;
};

class CFX_FixedStore : public IFX_MemoryAllocator, public CFX_Target {
 public:
  CFX_FixedStore(size_t iBlockSize, size_t iBlockNumsInChunk);
  ~CFX_FixedStore() override;
  void* Alloc(size_t size) override;
  void Free(void* pBlock) override;

 protected:
  FX_FIXEDSTORECHUNK* AllocChunk();

  size_t m_iBlockSize;
  size_t m_iDefChunkSize;
  FX_FIXEDSTORECHUNK* m_pChunk;
};

}  // namespace

#define FX_4BYTEALIGN(size) (((size) + 3) & ~3)

IFX_MemoryAllocator* IFX_MemoryAllocator::Create(FX_ALLOCTYPE eType,
                                                 size_t chunkSize,
                                                 size_t blockSize) {
  switch (eType) {
    case FX_ALLOCTYPE_Static:
      return new CFX_StaticStore(chunkSize);
    case FX_ALLOCTYPE_Fixed:
      return new CFX_FixedStore(blockSize, chunkSize);
    default:
      ASSERT(0);
      return nullptr;
  }
}

CFX_StaticStore::CFX_StaticStore(size_t iDefChunkSize)
    : m_iAllocatedSize(0),
      m_iDefChunkSize(iDefChunkSize),
      m_pChunk(nullptr),
      m_pLastChunk(nullptr) {
  ASSERT(m_iDefChunkSize != 0);
}
CFX_StaticStore::~CFX_StaticStore() {
  FX_STATICSTORECHUNK* pChunk = m_pChunk;
  while (pChunk) {
    FX_STATICSTORECHUNK* pNext = pChunk->pNextChunk;
    FX_Free(pChunk);
    pChunk = pNext;
  }
}
FX_STATICSTORECHUNK* CFX_StaticStore::AllocChunk(size_t size) {
  ASSERT(size != 0);
  FX_STATICSTORECHUNK* pChunk = (FX_STATICSTORECHUNK*)FX_Alloc(
      uint8_t, sizeof(FX_STATICSTORECHUNK) + size);
  pChunk->iChunkSize = size;
  pChunk->iFreeSize = size;
  pChunk->pNextChunk = nullptr;
  if (!m_pLastChunk) {
    m_pChunk = pChunk;
  } else {
    m_pLastChunk->pNextChunk = pChunk;
  }
  m_pLastChunk = pChunk;
  return pChunk;
}
FX_STATICSTORECHUNK* CFX_StaticStore::FindChunk(size_t size) {
  ASSERT(size != 0);
  if (!m_pLastChunk || m_pLastChunk->iFreeSize < size) {
    return AllocChunk(std::max(m_iDefChunkSize, size));
  }
  return m_pLastChunk;
}
void* CFX_StaticStore::Alloc(size_t size) {
  size = FX_4BYTEALIGN(size);
  ASSERT(size != 0);
  FX_STATICSTORECHUNK* pChunk = FindChunk(size);
  ASSERT(pChunk->iFreeSize >= size);
  uint8_t* p = (uint8_t*)pChunk;
  p += sizeof(FX_STATICSTORECHUNK) + pChunk->iChunkSize - pChunk->iFreeSize;
  pChunk->iFreeSize -= size;
  m_iAllocatedSize += size;
  return p;
}
size_t CFX_StaticStore::SetDefChunkSize(size_t size) {
  ASSERT(size != 0);
  size_t v = m_iDefChunkSize;
  m_iDefChunkSize = size;
  return v;
}
CFX_FixedStore::CFX_FixedStore(size_t iBlockSize, size_t iBlockNumsInChunk)
    : m_iBlockSize(FX_4BYTEALIGN(iBlockSize)),
      m_iDefChunkSize(FX_4BYTEALIGN(iBlockNumsInChunk)),
      m_pChunk(nullptr) {
  ASSERT(m_iBlockSize != 0 && m_iDefChunkSize != 0);
}
CFX_FixedStore::~CFX_FixedStore() {
  FX_FIXEDSTORECHUNK* pChunk = m_pChunk;
  while (pChunk) {
    FX_FIXEDSTORECHUNK* pNext = pChunk->pNextChunk;
    FX_Free(pChunk);
    pChunk = pNext;
  }
}
FX_FIXEDSTORECHUNK* CFX_FixedStore::AllocChunk() {
  int32_t iTotalSize = sizeof(FX_FIXEDSTORECHUNK) + m_iDefChunkSize +
                       m_iBlockSize * m_iDefChunkSize;
  FX_FIXEDSTORECHUNK* pChunk =
      (FX_FIXEDSTORECHUNK*)FX_Alloc(uint8_t, iTotalSize);
  if (!pChunk)
    return nullptr;

  FXSYS_memset(pChunk->FirstFlag(), 0, m_iDefChunkSize);
  pChunk->pNextChunk = m_pChunk;
  pChunk->iChunkSize = m_iDefChunkSize;
  pChunk->iFreeNum = m_iDefChunkSize;
  m_pChunk = pChunk;
  return pChunk;
}
void* CFX_FixedStore::Alloc(size_t size) {
  if (size > m_iBlockSize) {
    return nullptr;
  }
  FX_FIXEDSTORECHUNK* pChunk = m_pChunk;
  while (pChunk) {
    if (pChunk->iFreeNum > 0) {
      break;
    }
    pChunk = pChunk->pNextChunk;
  }
  if (!pChunk) {
    pChunk = AllocChunk();
  }
  uint8_t* pFlags = pChunk->FirstFlag();
  size_t i = 0;
  for (; i < pChunk->iChunkSize; i++)
    if (pFlags[i] == 0) {
      break;
    }
  ASSERT(i < pChunk->iChunkSize);
  pFlags[i] = 1;
  pChunk->iFreeNum--;
  return pChunk->FirstBlock() + i * m_iBlockSize;
}
void CFX_FixedStore::Free(void* pBlock) {
  FX_FIXEDSTORECHUNK* pPrior = nullptr;
  FX_FIXEDSTORECHUNK* pChunk = m_pChunk;
  uint8_t* pStart = nullptr;
  uint8_t* pEnd;
  while (pChunk) {
    pStart = pChunk->FirstBlock();
    if (pBlock >= pStart) {
      pEnd = pStart + m_iBlockSize * pChunk->iChunkSize;
      if (pBlock < pEnd) {
        break;
      }
    }
    pPrior = pChunk, pChunk = pChunk->pNextChunk;
  }
  ASSERT(pChunk);
  size_t iPos = ((uint8_t*)pBlock - pStart) / m_iBlockSize;
  ASSERT(iPos < pChunk->iChunkSize);
  uint8_t* pFlags = pChunk->FirstFlag();
  if (pFlags[iPos] == 0) {
    return;
  }
  pFlags[iPos] = 0;
  pChunk->iFreeNum++;
  if (pChunk->iFreeNum == pChunk->iChunkSize) {
    if (!pPrior) {
      m_pChunk = pChunk->pNextChunk;
    } else {
      pPrior->pNextChunk = pChunk->pNextChunk;
    }
    FX_Free(pChunk);
  }
}
size_t CFX_FixedStore::SetDefChunkSize(size_t iChunkSize) {
  ASSERT(iChunkSize != 0);
  size_t v = m_iDefChunkSize;
  m_iDefChunkSize = FX_4BYTEALIGN(iChunkSize);
  return v;
}

#endif  // MEMORY_TOOL_REPLACES_ALLOCATOR
<|endoftext|>


<commit_before>#include "CorrectionEngine.h"
#include "parser/TaobaoParser.h"
#include "StringUtil.h"
#include "evaluate/EvaluatorFactory.h"

#include <boost/filesystem.hpp>
#include <boost/algorithm/string.hpp>
#include <knlp/normalize.h>
#include <util/ustring/UString.h>

#include <time.h>
#include <stdlib.h>
#include <ctype.h>

namespace sf1r
{
namespace Recommend
{

static double factorForPinYin(const std::string& self, const std::string& userQuery)
{
    izenelib::util::UString uself(self, izenelib::util::UString::UTF_8);
    izenelib::util::UString ustr(userQuery, izenelib::util::UString::UTF_8);
    double s = 1.0;
    if (uself.isAllChineseChar())
    {
        if (uself.length() != ustr.length())
            return 1e-6;
        if (2 == uself.length())
        {
            if (uself[0] != ustr[0])
            {
                if (uself[1] != ustr[1])
                    s /= 10;
                s /= 2;
            }
            else
                s *= 1.28;
        }
        if (2 < uself.length())
        {
            uint32_t n = 0;
            for (std::size_t i = 0; i < uself.length(); i++)
            {
                if (uself[i] == ustr[i])
                    n++;
            }
            s *= n;
            s /= (uself.length() -n);
        }
    }
    return s;
}

static double factorForPrefix(const std::string& self, const std::string& userQuery)
{
    izenelib::util::UString uself(self, izenelib::util::UString::UTF_8);
    izenelib::util::UString ustr(userQuery, izenelib::util::UString::UTF_8);
    double s = 1.0;
    if (PrefixTable::isPrefixEnglish(userQuery))
        s *= 20;

    // iphone5 => iphone 5
    bool selfHasChinese = false;
    for (std::size_t i = 0; i < uself.length(); i++)
    {
        if (uself.isChineseChar(i))
        {
            selfHasChinese = true;
            break;
        }
    }
    if (!selfHasChinese)
    {
        bool ustrHasChinese = false;
        for (std::size_t i = 0; i < ustr.length(); i++)
        {
            if (ustr.isChineseChar(i))
            {
                ustrHasChinese = true;
                break;
            }
        }
        if (!ustrHasChinese)
        {
            std::size_t selfL = self.size();
            std::size_t userL = userQuery.size();
            if (selfL < userL)
            {
                std::size_t i = 0, j = 0;
                while (true)
                {
                    if ((i >= selfL) || (j >= userL))
                        break;
                    if (self[i] == userQuery[j])
                    {
                        i++;
                        j++;
                    }
                    else if (' ' == self[i])
                    {
                        break;
                    }
                    else if (' ' == userQuery[j])
                    {
                        j++;
                    }
                    else
                    {
                        break;
                    }
                }
                if ((i == selfL) && (j == userL))
                    s *= 400;
            }
        }
    }

    // digit change iphone6 => iphone5
    std::size_t selfL = uself.length();
    std::size_t ustrL = ustr.length();
    std::size_t i = 0;
    std::size_t j = 0;
    while (true)
    {
        if ((i >= selfL) || (j >= ustrL))
            break;
        if (uself[i] == ustr[j])
        {
            i++;
            j++;
        }
        else if (uself.isSpaceChar(i))
        {
            i++;
        }
        else if (ustr.isSpaceChar(j))
        {
            j++;
        }
        else if (uself.isDigitChar(i))
        {
            if (ustr.isDigitChar(j))
                s /= 100;
            else if (ustr.isChineseChar(j))
                s /= 200;
            else
                s /= 150;
            i++;
            j++;
        }
        else if (ustr.isDigitChar(j))
        {
            if (uself.isDigitChar(i))
                s /= 100;
            else if (uself.isChineseChar(i))
                s /= 200;
            else
                s /= 150;
            i++;
            j++;
        }
        else
        {
            i++;
            j++;
        }
    }
    if ((i < selfL) && (uself.isDigitChar(i)))
        s /= 150;
    if (selfL >= ustrL)
        s /= 1024;

    std::size_t nself = 0;
    for (i = 0; i < selfL; i++)
    {
        if (!uself.isSpaceChar(i))
            nself++;
    }
    std::size_t nstr = 0;
    for (i = 0; i < ustrL; i++)
    {
        if (!ustr.isSpaceChar(i))
            nstr++;
    }
    if (nself != nstr)
        s /= 1024;
    return s;
}

static std::string timestamp = ".CorrectionEngineTimestamp";

CorrectionEngine::CorrectionEngine(const std::string& workdir)
    : pinyin_(NULL)
    , prefix_(NULL)
    , filter_(NULL)
    , parsers_(NULL)
    , pyConverter_(NULL)
    , pyApproximator_(NULL)
    , timestamp_(0)
    , workdir_(workdir)
{
    if (!boost::filesystem::exists(workdir_))
    {
        boost::filesystem::create_directory(workdir_);
    }

    pinyin_ = new PinyinTable(workdir_);
    prefix_ = new PrefixTable(workdir_);
    filter_ = new Filter(workdir_ + "/filter/");
    parsers_ = new ParserFactory();

    UQCateEngine::workdir = workdir_;
    UQCateEngine::getInstance().lock((void*)this);

    std::string path = workdir_;
    path += "/";
    path += timestamp;

    std::ifstream in;
    in.open(path.c_str(), std::ifstream::in);
    in>>timestamp_;
    in.close();
}

CorrectionEngine:: ~CorrectionEngine()
{
    if (NULL != pinyin_)
    {
        delete pinyin_;
        pinyin_ = NULL;
    }
    if (NULL != prefix_)
    {
        delete prefix_;
        prefix_ = NULL;
    }
    if (NULL != filter_)
    {
        delete filter_;
        filter_ = NULL;
    }
    if (NULL != parsers_)
    {
        delete parsers_;
        parsers_ = NULL;
    }
}

void CorrectionEngine::evaluate(const std::string& path, std::string& sResult) const
{
    std::string resource;
    if (!boost::filesystem::exists(path))
        resource = workdir_;
    else if(!boost::filesystem::is_directory(path))
        resource = workdir_;
    else
        resource = path;

    std::ofstream out;
    out.open("errors", std::ofstream::out | std::ofstream::trunc);
    boost::filesystem::directory_iterator end;
    for(boost::filesystem::directory_iterator it(resource) ; it != end ; ++it)
    {
        const std::string p = it->path().string();
        if(boost::filesystem::is_regular_file(p))
        {
            if (!EvaluatorFactory::isValid(p))
                continue;

            Evaluator* evaluator = EvaluatorFactory::load(p);
            Evaluator::iterator it = evaluator->begin();
            for (; it != evaluator->end(); ++it)
            {
                std::string result;
                double freq = 0.0;
                correct(it->userQuery(), result, freq);
                evaluator->isCorrect(out, result);
            }
            EvaluatorFactory::destory(evaluator);
        }
    }
    out.close();
    Evaluator::toString(sResult);
    Evaluator::clear();
}

bool CorrectionEngine::isNeedBuild(const std::string& path) const
{
    std::string resource;
    if (!boost::filesystem::exists(path))
        resource = workdir_;
    else if(!boost::filesystem::is_directory(path))
        resource = workdir_;
    else
        resource = path;

    boost::filesystem::directory_iterator end;
    for(boost::filesystem::directory_iterator it(resource) ; it != end ; ++it)
    {
        const std::string p = it->path().string();
        if(boost::filesystem::is_regular_file(p))
        {
            //std::cout<<p<<"\n";
            if (!parsers_->isValid(p))
                continue;
            std::time_t mt = boost::filesystem::last_write_time(it->path());
            if (mt > timestamp_)
                return true;
        }
    }
    return filter_->isNeedBuild(path +"/filter/");
}

void CorrectionEngine::buildEngine(const std::string& path)
{
    clear();

    std::string resource;
    if (!boost::filesystem::exists(path))
        resource = workdir_;
    else if(!boost::filesystem::is_directory(path))
        resource = workdir_;
    else
        resource = path;

    boost::filesystem::directory_iterator end;
    for(boost::filesystem::directory_iterator it(resource) ; it != end ; ++it)
    {
        const std::string p = it->path().string();
        if(boost::filesystem::is_regular_file(p))
        {
            //std::cout<<p<<"\n";
            if (!parsers_->isValid(p))
                continue;
            Parser* parser = parsers_->load(p);
            if (NULL == parser)
                continue;
            Parser::iterator it = parser->begin();
            for (; it != parser->end(); ++it)
            {
                //std::cout<<it->userQuery()<<" : "<<it->freq()<<"\n";
                processQuery(it->userQuery(), it->category(), it->freq());
            }
            parsers_->destory(parser);
        }
    }

    filter_->buildFilter(path + "/filter/");
    timestamp_ = time(NULL);
    flush();
}

void CorrectionEngine::processQuery(const std::string& str, const std::string& category, const uint32_t freq)
{
    std::string userQuery = str;
    try
    {
        ilplib::knlp::Normalize::normalize(userQuery);
    }
    catch(...)
    {
    }

    std::vector<std::string> pinyin;
    if (NULL != pyConverter_)
    {
        (*pyConverter_)(userQuery, pinyin);
    }
    for (std::size_t i = 0; i < pinyin.size(); i++)
    {
        pinyin_->insert(userQuery, pinyin[i], freq);
    }

    prefix_->insert(userQuery, freq);
    UQCateEngine::getInstance().insert(str, category, freq);
}

void CorrectionEngine::clear()
{
    pinyin_->clear();
    prefix_->clear();
    filter_->clear();
    UQCateEngine::getInstance().clear();
}

void CorrectionEngine::flush() const
{
    pinyin_->flush();
    prefix_->flush();
    filter_->flush();
    UQCateEngine::getInstance().flush();

    std::string path = workdir_;
    path += "/";
    path += timestamp;

    std::ofstream out;
    out.open(path.c_str(), std::ofstream::out | std::ofstream::trunc);
    out<<timestamp_;
    out.close();
}

bool CorrectionEngine::correct(const std::string& str, std::string& results, double& freq) const
{
    std::string userQuery = str;
    try
    {
        ilplib::knlp::Normalize::normalize(userQuery);
    }
    catch(...)
    {
    }
    izenelib::util::UString uself(userQuery, izenelib::util::UString::UTF_8);
    if (uself.length() <= 1)
        return false;

    if (filter_->isFilter(userQuery))
    {
        return false;
    }
    std::vector<std::string> pinyin;
    bool isUserQueryHasChinese = false;
    if (NULL != pyConverter_)
    {
        isUserQueryHasChinese = (*pyConverter_)(userQuery, pinyin);
    }

    UserQuery self(userQuery, 0);
    FreqStringVector candidates;

    // from pinyin
    double factor = 100;
    boost::unordered_map<std::string, bool> accurate;
    for (std::size_t i = 0; i < pinyin.size(); i++)
    {
        UserQueryList uqList;
        pinyin_->search(pinyin[i], uqList);
        accurate[pinyin[i]] = true;
//std::cout<<pinyin[i]<<"\t-------------\n";
        UserQueryList::iterator it = uqList.begin();
        for (; it != uqList.end(); it++)
        {
            if (it->userQuery() != self.userQuery())
            {
                if (!UQCateEngine::getInstance().cateEqual(self.userQuery(), it->userQuery(), 10))
                    continue;
                double s = factorForPinYin(self.userQuery(), it->userQuery());
//std::cout<<it->userQuery()<<" : "<<it->freq()<<" : "<<s<<"\n";
                candidates.push_back(FreqString(it->userQuery(), it->freq() * factor * s));
            }
        }
    }

    // from approximate pinyin
    pinyin.clear();
    bool isUserQueryPinYin = false;
    if ((NULL != pyApproximator_) && (candidates.empty() || (!isUserQueryHasChinese)))
    {
        isUserQueryPinYin = (*pyApproximator_)(userQuery, pinyin);
        factor = 50;
        for (std::size_t i = 0; i < pinyin.size(); i++)
        {
            UserQueryList uqList;
            if (accurate.end() != accurate.find(pinyin[i]))
                continue;
            pinyin_->search(pinyin[i], uqList);
//std::cout<<pinyin[i]<<"\t-------------\n";
            UserQueryList::iterator it = uqList.begin();
            for (; it != uqList.end(); it++)
            {
                if (it->userQuery() != self.userQuery())
                {
                    if (!UQCateEngine::getInstance().cateEqual(self.userQuery(), it->userQuery(), 100))
                        continue;
                    double s = factorForPinYin(self.userQuery(), it->userQuery());
//std::cout<<it->userQuery()<<" : "<<it->freq()<<" : "<<s<<"\n";
                    candidates.push_back(FreqString(it->userQuery(), it->freq() * factor * s));
                }
            }
        }
    }
    pinyin.clear();
    accurate.clear();

    // from prefix
    factor = 1;
    UserQueryList uqList;
    prefix_->search(userQuery, uqList);
    UserQueryList::iterator it = uqList.begin();
//std::cout<<"PREFIX::\t-----------\n";
    for (; it != uqList.end(); it++)
    {
        if (it->userQuery() == self.userQuery())
        {
            self.setFreq(self.freq() + it->freq());
        }
        else
        {
            if (!UQCateEngine::getInstance().cateEqual(self.userQuery(), it->userQuery(), 100))
                continue;
            double s = factorForPrefix(self.userQuery(), it->userQuery());
//std::cout<<it->userQuery()<<" : "<<s<<"\n";
            candidates.push_back(FreqString(it->userQuery(), it->freq() * factor * s));
        }
    }

    if (candidates.empty())
        return false;

    factor = 1000;
    double s = isUserQueryPinYin ? 0.1 : 1;
    self.setFreq(self.freq() * factor * s);
    if (self.freq() < 1e-2)
    {
        self.setFreq(100);
    }

    FreqString max = StringUtil::max(candidates);
    const double selfFreq = self.freq();
    const double maxFreq = max.getFreq();

//std::cout<<self.freq()<<"\t:\t"<<max.getFreq()<<"\n";
//std::cout<<self.userQuery()<<"\t:\t"<<max.getString()<<"\n";
    if (2.4 * selfFreq < maxFreq)
    {
        results = max.getString();
        freq = maxFreq / selfFreq;
        return true;
    }
    return false;
}

}
}
<commit_msg>Remove only one charactor.<commit_after>#include "CorrectionEngine.h"
#include "parser/TaobaoParser.h"
#include "StringUtil.h"
#include "evaluate/EvaluatorFactory.h"

#include <boost/filesystem.hpp>
#include <boost/algorithm/string.hpp>
#include <knlp/normalize.h>
#include <util/ustring/UString.h>

#include <time.h>
#include <stdlib.h>
#include <ctype.h>

namespace sf1r
{
namespace Recommend
{

static double factorForPinYin(const std::string& self, const std::string& userQuery)
{
    izenelib::util::UString uself(self, izenelib::util::UString::UTF_8);
    izenelib::util::UString ustr(userQuery, izenelib::util::UString::UTF_8);
    double s = 1.0;
    if (uself.isAllChineseChar())
    {
        if (uself.length() != ustr.length())
            return 1e-6;
        if (2 == uself.length())
        {
            if (uself[0] != ustr[0])
            {
                if (uself[1] != ustr[1])
                    s /= 10;
                s /= 2;
            }
            else
                s *= 1.28;
        }
        if (2 < uself.length())
        {
            uint32_t n = 0;
            for (std::size_t i = 0; i < uself.length(); i++)
            {
                if (uself[i] == ustr[i])
                    n++;
            }
            s *= n;
            s /= (uself.length() -n);
        }
    }
    return s;
}

static double factorForPrefix(const std::string& self, const std::string& userQuery)
{
    izenelib::util::UString uself(self, izenelib::util::UString::UTF_8);
    izenelib::util::UString ustr(userQuery, izenelib::util::UString::UTF_8);
    double s = 1.0;
    if (PrefixTable::isPrefixEnglish(userQuery))
        s *= 20;

    // iphone5 => iphone 5
    bool selfHasChinese = false;
    for (std::size_t i = 0; i < uself.length(); i++)
    {
        if (uself.isChineseChar(i))
        {
            selfHasChinese = true;
            break;
        }
    }
    if (!selfHasChinese)
    {
        bool ustrHasChinese = false;
        for (std::size_t i = 0; i < ustr.length(); i++)
        {
            if (ustr.isChineseChar(i))
            {
                ustrHasChinese = true;
                break;
            }
        }
        if (!ustrHasChinese)
        {
            std::size_t selfL = self.size();
            std::size_t userL = userQuery.size();
            if (selfL < userL)
            {
                std::size_t i = 0, j = 0;
                while (true)
                {
                    if ((i >= selfL) || (j >= userL))
                        break;
                    if (self[i] == userQuery[j])
                    {
                        i++;
                        j++;
                    }
                    else if (' ' == self[i])
                    {
                        break;
                    }
                    else if (' ' == userQuery[j])
                    {
                        j++;
                    }
                    else
                    {
                        break;
                    }
                }
                if ((i == selfL) && (j == userL))
                    s *= 400;
            }
        }
    }

    // digit change iphone6 => iphone5
    std::size_t selfL = uself.length();
    std::size_t ustrL = ustr.length();
    std::size_t i = 0;
    std::size_t j = 0;
    while (true)
    {
        if ((i >= selfL) || (j >= ustrL))
            break;
        if (uself[i] == ustr[j])
        {
            i++;
            j++;
        }
        else if (uself.isSpaceChar(i))
        {
            i++;
        }
        else if (ustr.isSpaceChar(j))
        {
            j++;
        }
        else if (uself.isDigitChar(i))
        {
            if (ustr.isDigitChar(j))
                s /= 100;
            else if (ustr.isChineseChar(j))
                s /= 200;
            else
                s /= 150;
            i++;
            j++;
        }
        else if (ustr.isDigitChar(j))
        {
            if (uself.isDigitChar(i))
                s /= 100;
            else if (uself.isChineseChar(i))
                s /= 200;
            else
                s /= 150;
            i++;
            j++;
        }
        else
        {
            i++;
            j++;
        }
    }
    if ((i < selfL) && (uself.isDigitChar(i)))
        s /= 150;
    if (selfL >= ustrL)
        s /= 1024;

    std::size_t nself = 0;
    for (i = 0; i < selfL; i++)
    {
        if (!uself.isSpaceChar(i))
            nself++;
    }
    std::size_t nstr = 0;
    for (i = 0; i < ustrL; i++)
    {
        if (!ustr.isSpaceChar(i))
            nstr++;
    }
    if (nself != nstr)
        s /= 1024;
    return s;
}

static std::string timestamp = ".CorrectionEngineTimestamp";

CorrectionEngine::CorrectionEngine(const std::string& workdir)
    : pinyin_(NULL)
    , prefix_(NULL)
    , filter_(NULL)
    , parsers_(NULL)
    , pyConverter_(NULL)
    , pyApproximator_(NULL)
    , timestamp_(0)
    , workdir_(workdir)
{
    if (!boost::filesystem::exists(workdir_))
    {
        boost::filesystem::create_directory(workdir_);
    }

    pinyin_ = new PinyinTable(workdir_);
    prefix_ = new PrefixTable(workdir_);
    filter_ = new Filter(workdir_ + "/filter/");
    parsers_ = new ParserFactory();

    UQCateEngine::workdir = workdir_;
    UQCateEngine::getInstance().lock((void*)this);

    std::string path = workdir_;
    path += "/";
    path += timestamp;

    std::ifstream in;
    in.open(path.c_str(), std::ifstream::in);
    in>>timestamp_;
    in.close();
}

CorrectionEngine:: ~CorrectionEngine()
{
    if (NULL != pinyin_)
    {
        delete pinyin_;
        pinyin_ = NULL;
    }
    if (NULL != prefix_)
    {
        delete prefix_;
        prefix_ = NULL;
    }
    if (NULL != filter_)
    {
        delete filter_;
        filter_ = NULL;
    }
    if (NULL != parsers_)
    {
        delete parsers_;
        parsers_ = NULL;
    }
}

void CorrectionEngine::evaluate(const std::string& path, std::string& sResult) const
{
    std::string resource;
    if (!boost::filesystem::exists(path))
        resource = workdir_;
    else if(!boost::filesystem::is_directory(path))
        resource = workdir_;
    else
        resource = path;

    std::ofstream out;
    out.open("errors", std::ofstream::out | std::ofstream::trunc);
    boost::filesystem::directory_iterator end;
    for(boost::filesystem::directory_iterator it(resource) ; it != end ; ++it)
    {
        const std::string p = it->path().string();
        if(boost::filesystem::is_regular_file(p))
        {
            if (!EvaluatorFactory::isValid(p))
                continue;

            Evaluator* evaluator = EvaluatorFactory::load(p);
            Evaluator::iterator it = evaluator->begin();
            for (; it != evaluator->end(); ++it)
            {
                std::string result;
                double freq = 0.0;
                correct(it->userQuery(), result, freq);
                evaluator->isCorrect(out, result);
            }
            EvaluatorFactory::destory(evaluator);
        }
    }
    out.close();
    Evaluator::toString(sResult);
    Evaluator::clear();
}

bool CorrectionEngine::isNeedBuild(const std::string& path) const
{
    std::string resource;
    if (!boost::filesystem::exists(path))
        resource = workdir_;
    else if(!boost::filesystem::is_directory(path))
        resource = workdir_;
    else
        resource = path;

    boost::filesystem::directory_iterator end;
    for(boost::filesystem::directory_iterator it(resource) ; it != end ; ++it)
    {
        const std::string p = it->path().string();
        if(boost::filesystem::is_regular_file(p))
        {
            //std::cout<<p<<"\n";
            if (!parsers_->isValid(p))
                continue;
            std::time_t mt = boost::filesystem::last_write_time(it->path());
            if (mt > timestamp_)
                return true;
        }
    }
    return filter_->isNeedBuild(path +"/filter/");
}

void CorrectionEngine::buildEngine(const std::string& path)
{
    clear();

    std::string resource;
    if (!boost::filesystem::exists(path))
        resource = workdir_;
    else if(!boost::filesystem::is_directory(path))
        resource = workdir_;
    else
        resource = path;

    boost::filesystem::directory_iterator end;
    for(boost::filesystem::directory_iterator it(resource) ; it != end ; ++it)
    {
        const std::string p = it->path().string();
        if(boost::filesystem::is_regular_file(p))
        {
            //std::cout<<p<<"\n";
            if (!parsers_->isValid(p))
                continue;
            Parser* parser = parsers_->load(p);
            if (NULL == parser)
                continue;
            Parser::iterator it = parser->begin();
            for (; it != parser->end(); ++it)
            {
                //std::cout<<it->userQuery()<<" : "<<it->freq()<<"\n";
                processQuery(it->userQuery(), it->category(), it->freq());
            }
            parsers_->destory(parser);
        }
    }

    filter_->buildFilter(path + "/filter/");
    timestamp_ = time(NULL);
    flush();
}

void CorrectionEngine::processQuery(const std::string& str, const std::string& category, const uint32_t freq)
{
    std::string userQuery = str;
    try
    {
        ilplib::knlp::Normalize::normalize(userQuery);
    }
    catch(...)
    {
    }

    std::vector<std::string> pinyin;
    if (NULL != pyConverter_)
    {
        (*pyConverter_)(userQuery, pinyin);
    }
    for (std::size_t i = 0; i < pinyin.size(); i++)
    {
        pinyin_->insert(userQuery, pinyin[i], freq);
    }

    prefix_->insert(userQuery, freq);
    UQCateEngine::getInstance().insert(str, category, freq);
}

void CorrectionEngine::clear()
{
    pinyin_->clear();
    prefix_->clear();
    filter_->clear();
    UQCateEngine::getInstance().clear();
}

void CorrectionEngine::flush() const
{
    pinyin_->flush();
    prefix_->flush();
    filter_->flush();
    UQCateEngine::getInstance().flush();

    std::string path = workdir_;
    path += "/";
    path += timestamp;

    std::ofstream out;
    out.open(path.c_str(), std::ofstream::out | std::ofstream::trunc);
    out<<timestamp_;
    out.close();
}

bool CorrectionEngine::correct(const std::string& str, std::string& results, double& freq) const
{
    std::string userQuery = str;
    try
    {
        ilplib::knlp::Normalize::normalize(userQuery);
    }
    catch(...)
    {
    }
    izenelib::util::UString uself(userQuery, izenelib::util::UString::UTF_8);
    if (uself.length() <= 1)
        return false;

    if (filter_->isFilter(userQuery))
    {
        return false;
    }
    std::vector<std::string> pinyin;
    bool isUserQueryHasChinese = false;
    if (NULL != pyConverter_)
    {
        isUserQueryHasChinese = (*pyConverter_)(userQuery, pinyin);
    }

    UserQuery self(userQuery, 0);
    FreqStringVector candidates;

    // from pinyin
    double factor = 100;
    boost::unordered_map<std::string, bool> accurate;
    for (std::size_t i = 0; i < pinyin.size(); i++)
    {
        UserQueryList uqList;
        pinyin_->search(pinyin[i], uqList);
        accurate[pinyin[i]] = true;
//std::cout<<pinyin[i]<<"\t-------------\n";
        UserQueryList::iterator it = uqList.begin();
        for (; it != uqList.end(); it++)
        {
            if (it->userQuery() != self.userQuery())
            {
                if (!UQCateEngine::getInstance().cateEqual(self.userQuery(), it->userQuery(), 10))
                    continue;
                double s = factorForPinYin(self.userQuery(), it->userQuery());
//std::cout<<it->userQuery()<<" : "<<it->freq()<<" : "<<s<<"\n";
                candidates.push_back(FreqString(it->userQuery(), it->freq() * factor * s));
            }
        }
    }

    // from approximate pinyin
    pinyin.clear();
    bool isUserQueryPinYin = false;
    if ((NULL != pyApproximator_) && (candidates.empty() || (!isUserQueryHasChinese)))
    {
        isUserQueryPinYin = (*pyApproximator_)(userQuery, pinyin);
        factor = 50;
        for (std::size_t i = 0; i < pinyin.size(); i++)
        {
            UserQueryList uqList;
            if (accurate.end() != accurate.find(pinyin[i]))
                continue;
            pinyin_->search(pinyin[i], uqList);
//std::cout<<pinyin[i]<<"\t-------------\n";
            UserQueryList::iterator it = uqList.begin();
            for (; it != uqList.end(); it++)
            {
                if (it->userQuery() != self.userQuery())
                {
                    if (!UQCateEngine::getInstance().cateEqual(self.userQuery(), it->userQuery(), 100))
                        continue;
                    double s = factorForPinYin(self.userQuery(), it->userQuery());
//std::cout<<it->userQuery()<<" : "<<it->freq()<<" : "<<s<<"\n";
                    candidates.push_back(FreqString(it->userQuery(), it->freq() * factor * s));
                }
            }
        }
    }
    pinyin.clear();
    accurate.clear();

    // from prefix
    factor = 1;
    UserQueryList uqList;
    prefix_->search(userQuery, uqList);
    UserQueryList::iterator it = uqList.begin();
//std::cout<<"PREFIX::\t-----------\n";
    for (; it != uqList.end(); it++)
    {
        if (it->userQuery() == self.userQuery())
        {
            self.setFreq(self.freq() + it->freq());
        }
        else
        {
            if (!UQCateEngine::getInstance().cateEqual(self.userQuery(), it->userQuery(), 100))
                continue;
            double s = factorForPrefix(self.userQuery(), it->userQuery());
//std::cout<<it->userQuery()<<" : "<<s<<"\n";
            candidates.push_back(FreqString(it->userQuery(), it->freq() * factor * s));
        }
    }

    if (candidates.empty())
        return false;

    factor = 1000;
    double s = isUserQueryPinYin ? 0.1 : 1;
    self.setFreq(self.freq() * factor * s);
    if (self.freq() < 1e-2)
    {
        self.setFreq(100);
    }

    FreqString max = StringUtil::max(candidates);
    const double selfFreq = self.freq();
    const double maxFreq = max.getFreq();
    izenelib::util::UString umax(max.getString(), izenelib::util::UString::UTF_8);
    if (umax.length() <= 1)
        return false;

//std::cout<<self.freq()<<"\t:\t"<<max.getFreq()<<"\n";
//std::cout<<self.userQuery()<<"\t:\t"<<max.getString()<<"\n";
    if (2.4 * selfFreq < maxFreq)
    {
        results = max.getString();
        freq = maxFreq / selfFreq;
        return true;
    }
    return false;
}

}
}
<|endoftext|>


<commit_before>// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/component_updater/widevine_cdm_component_installer.h"

#include <string.h>

#include <vector>

#include "base/base_paths.h"
#include "base/bind.h"
#include "base/command_line.h"
#include "base/compiler_specific.h"
#include "base/file_util.h"
#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "base/string_util.h"
#include "base/values.h"
#include "base/version.h"
#include "build/build_config.h"
#include "chrome/browser/component_updater/component_updater_service.h"
#include "chrome/browser/plugins/plugin_prefs.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/widevine_cdm_constants.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/plugin_service.h"
#include "content/public/common/pepper_plugin_info.h"
#include "third_party/widevine/cdm/widevine_cdm_common.h"

#include "widevine_cdm_version.h"  // In SHARED_INTERMEDIATE_DIR.

using content::BrowserThread;
using content::PluginService;

namespace {

// TODO(xhwang): Move duplicate code among all component installer
// implementations to some common place.

#if defined(WIDEVINE_CDM_AVAILABLE) && defined(WIDEVINE_CDM_IS_COMPONENT)

// CRX hash. The extension id is: pdkaonnflpjcgibpgaanildgengnihcm.
const uint8 kSha2Hash[] = { 0xf3, 0xa0, 0xed, 0xd5, 0xbf, 0x92, 0x68, 0x1f,
                            0x60, 0x0d, 0x8b, 0x36, 0x4d, 0x6d, 0x87, 0x2c,
                            0x86, 0x61, 0x12, 0x20, 0x21, 0xf8, 0x94, 0xdd,
                            0xe1, 0xb6, 0xb4, 0x55, 0x34, 0x8c, 0x2e, 0x20 };

// File name of the Widevine CDM component manifest on different platforms.
const char kWidevineCdmManifestName[] = "WidevineCdm";

// Name of the Widevine CDM OS in the component manifest.
const char kWidevineCdmOperatingSystem[] =
#if defined(OS_MACOSX)
    "mac";
#elif defined(OS_WIN)
    "win";
#else  // OS_LINUX, etc. TODO(viettrungluu): Separate out Chrome OS and Android?
    "linux";
#endif

// Name of the Widevine CDM architecture in the component manifest.
const char kWidevineCdmArch[] =
#if defined(ARCH_CPU_X86)
    "ia32";
#elif defined(ARCH_CPU_X86_64)
    "x64";
#else  // TODO(viettrungluu): Support an ARM check?
    "???";
#endif

// If we don't have a Widevine CDM component, this is the version we claim.
const char kNullVersion[] = "0.0.0.0";

// The base directory on Windows looks like:
// <profile>\AppData\Local\Google\Chrome\User Data\WidevineCdm\.
base::FilePath GetWidevineCdmBaseDirectory() {
  base::FilePath result;
  PathService::Get(chrome::DIR_COMPONENT_WIDEVINE_CDM, &result);
  return result;
}

// Widevine CDM has the version encoded in the path so we need to enumerate the
// directories to find the full path.
// On success, |latest_dir| returns something like:
// <profile>\AppData\Local\Google\Chrome\User Data\WidevineCdm\10.3.44.555\.
// |latest_version| returns the corresponding version number. |older_dirs|
// returns directories of all older versions.
bool GetWidevineCdmDirectory(base::FilePath* latest_dir,
                             base::Version* latest_version,
                             std::vector<base::FilePath>* older_dirs) {
  base::FilePath base_dir = GetWidevineCdmBaseDirectory();
  bool found = false;
  file_util::FileEnumerator file_enumerator(
      base_dir, false, file_util::FileEnumerator::DIRECTORIES);
  for (base::FilePath path = file_enumerator.Next(); !path.value().empty();
       path = file_enumerator.Next()) {
    base::Version version(path.BaseName().MaybeAsASCII());
    if (!version.IsValid())
      continue;
    if (found) {
      if (version.CompareTo(*latest_version) > 0) {
        older_dirs->push_back(*latest_dir);
        *latest_dir = path;
        *latest_version = version;
      } else {
        older_dirs->push_back(path);
      }
    } else {
      *latest_dir = path;
      *latest_version = version;
      found = true;
    }
  }
  return found;
}

bool MakeWidevineCdmPluginInfo(const base::FilePath& path,
                               const base::Version& version,
                               content::PepperPluginInfo* plugin_info) {
  if (!version.IsValid() ||
      version.components().size() !=
          static_cast<size_t>(kWidevineCdmVersionNumComponents)) {
    return false;
  }

  plugin_info->is_internal = false;
  // Widevine CDM must run out of process.
  plugin_info->is_out_of_process = true;
  plugin_info->path = path;
  plugin_info->name = kWidevineCdmDisplayName;
  plugin_info->description = kWidevineCdmDescription;
  plugin_info->version = version.GetString();
  webkit::WebPluginMimeType widevine_cdm_mime_type(
      kWidevineCdmPluginMimeType,
      kWidevineCdmPluginExtension,
      kWidevineCdmPluginMimeTypeDescription);
  plugin_info->mime_types.push_back(widevine_cdm_mime_type);
  plugin_info->permissions = kWidevineCdmPluginPermissions;

  return true;
}

void RegisterWidevineCdmWithChrome(const base::FilePath& path,
                                   const base::Version& version) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  content::PepperPluginInfo plugin_info;
  if (!MakeWidevineCdmPluginInfo(path, version, &plugin_info))
    return;

  PluginService::GetInstance()->RegisterInternalPlugin(
      plugin_info.ToWebPluginInfo(), true);
  PluginService::GetInstance()->RefreshPlugins();
}

// Returns true if this browser is compatible with the given Widevine CDM
// manifest, with the version specified in the manifest in |version_out|.
bool CheckWidevineCdmManifest(const base::DictionaryValue& manifest,
                              base::Version* version_out) {
  std::string name;
  manifest.GetStringASCII("name", &name);

  if (name != kWidevineCdmManifestName)
    return false;

  std::string proposed_version;
  manifest.GetStringASCII("version", &proposed_version);
  base::Version version(proposed_version.c_str());
  if (!version.IsValid())
    return false;

  std::string os;
  manifest.GetStringASCII("x-widevine-cdm-os", &os);
  if (os != kWidevineCdmOperatingSystem)
    return false;

  std::string arch;
  manifest.GetStringASCII("x-widevine-cdm-arch", &arch);
  if (arch != kWidevineCdmArch)
    return false;

  *version_out = version;
  return true;
}

class WidevineCdmComponentInstaller : public ComponentInstaller {
 public:
  explicit WidevineCdmComponentInstaller(const base::Version& version);
  virtual ~WidevineCdmComponentInstaller() {}

  virtual void OnUpdateError(int error) OVERRIDE;
  virtual bool Install(const base::DictionaryValue& manifest,
                       const base::FilePath& unpack_path) OVERRIDE;

 private:
  base::Version current_version_;
};

WidevineCdmComponentInstaller::WidevineCdmComponentInstaller(
    const base::Version& version)
    : current_version_(version) {
  DCHECK(version.IsValid());
}

void WidevineCdmComponentInstaller::OnUpdateError(int error) {
  NOTREACHED() << "Widevine CDM update error: " << error;
}

bool WidevineCdmComponentInstaller::Install(
    const base::DictionaryValue& manifest,
    const base::FilePath& unpack_path) {
  base::Version version;
  if (!CheckWidevineCdmManifest(manifest, &version))
    return false;
  if (current_version_.CompareTo(version) > 0)
    return false;

  if (!file_util::PathExists(unpack_path.AppendASCII(kWidevineCdmFileName)))
    return false;

  base::FilePath adapter_source_path;
  PathService::Get(chrome::FILE_WIDEVINE_CDM_ADAPTER, &adapter_source_path);
  if (!file_util::PathExists(adapter_source_path))
    return false;

  // Passed the basic tests. Time to install it.
  base::FilePath install_path =
      GetWidevineCdmBaseDirectory().AppendASCII(version.GetString());
  if (file_util::PathExists(install_path))
    return false;
  if (!file_util::Move(unpack_path, install_path))
    return false;

  base::FilePath adapter_install_path =
      install_path.AppendASCII(kWidevineCdmAdapterFileName);
  if (!file_util::CopyFile(adapter_source_path, adapter_install_path))
    return false;

  // Installation is done. Now register the Widevine CDM with chrome.
  current_version_ = version;
  BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
      &RegisterWidevineCdmWithChrome, adapter_install_path, version));
  return true;
}

void FinishWidevineCdmUpdateRegistration(ComponentUpdateService* cus,
                                         const base::Version& version) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  CrxComponent widevine_cdm;
  widevine_cdm.name = "WidevineCdm";
  widevine_cdm.installer = new WidevineCdmComponentInstaller(version);
  widevine_cdm.version = version;
  widevine_cdm.pk_hash.assign(kSha2Hash, &kSha2Hash[sizeof(kSha2Hash)]);
  if (cus->RegisterComponent(widevine_cdm) != ComponentUpdateService::kOk) {
    NOTREACHED() << "Widevine CDM component registration failed.";
    return;
  }
}

void StartWidevineCdmUpdateRegistration(ComponentUpdateService* cus) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
  base::FilePath path = GetWidevineCdmBaseDirectory();
  if (!file_util::PathExists(path) && !file_util::CreateDirectory(path)) {
    NOTREACHED() << "Could not create Widevine CDM directory.";
    return;
  }

  base::Version version(kNullVersion);
  std::vector<base::FilePath> older_dirs;
  if (GetWidevineCdmDirectory(&path, &version, &older_dirs)) {
    if (file_util::PathExists(path.AppendASCII(kWidevineCdmAdapterFileName)) &&
        file_util::PathExists(path.AppendASCII(kWidevineCdmFileName))) {
      BrowserThread::PostTask(
          BrowserThread::UI, FROM_HERE,
          base::Bind(&RegisterWidevineCdmWithChrome, path, version));
    } else {
      file_util::Delete(path, true);
      version = base::Version(kNullVersion);
    }
  }

  BrowserThread::PostTask(
      BrowserThread::UI, FROM_HERE,
      base::Bind(&FinishWidevineCdmUpdateRegistration, cus, version));

  // Remove older versions of Widevine CDM.
  for (std::vector<base::FilePath>::iterator iter = older_dirs.begin();
       iter != older_dirs.end(); ++iter) {
    file_util::Delete(*iter, true);
  }
}

#endif  // defined(WIDEVINE_CDM_AVAILABLE) && defined(WIDEVINE_CDM_IS_COMPONENT)

}  // namespace

void RegisterWidevineCdmComponent(ComponentUpdateService* cus) {
#if defined(WIDEVINE_CDM_AVAILABLE) && defined(WIDEVINE_CDM_IS_COMPONENT)
  BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
                          base::Bind(&StartWidevineCdmUpdateRegistration, cus));
#endif  // defined(WIDEVINE_CDM_AVAILABLE) && defined(WIDEVINE_CDM_IS_COMPONENT)
}
<commit_msg>Fix Widevine CDM registration path when the component already exists.<commit_after>// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/component_updater/widevine_cdm_component_installer.h"

#include <string.h>

#include <vector>

#include "base/base_paths.h"
#include "base/bind.h"
#include "base/command_line.h"
#include "base/compiler_specific.h"
#include "base/file_util.h"
#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "base/string_util.h"
#include "base/values.h"
#include "base/version.h"
#include "build/build_config.h"
#include "chrome/browser/component_updater/component_updater_service.h"
#include "chrome/browser/plugins/plugin_prefs.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/widevine_cdm_constants.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/plugin_service.h"
#include "content/public/common/pepper_plugin_info.h"
#include "third_party/widevine/cdm/widevine_cdm_common.h"

#include "widevine_cdm_version.h"  // In SHARED_INTERMEDIATE_DIR.

using content::BrowserThread;
using content::PluginService;

namespace {

// TODO(xhwang): Move duplicate code among all component installer
// implementations to some common place.

#if defined(WIDEVINE_CDM_AVAILABLE) && defined(WIDEVINE_CDM_IS_COMPONENT)

// CRX hash. The extension id is: pdkaonnflpjcgibpgaanildgengnihcm.
const uint8 kSha2Hash[] = { 0xf3, 0xa0, 0xed, 0xd5, 0xbf, 0x92, 0x68, 0x1f,
                            0x60, 0x0d, 0x8b, 0x36, 0x4d, 0x6d, 0x87, 0x2c,
                            0x86, 0x61, 0x12, 0x20, 0x21, 0xf8, 0x94, 0xdd,
                            0xe1, 0xb6, 0xb4, 0x55, 0x34, 0x8c, 0x2e, 0x20 };

// File name of the Widevine CDM component manifest on different platforms.
const char kWidevineCdmManifestName[] = "WidevineCdm";

// Name of the Widevine CDM OS in the component manifest.
const char kWidevineCdmOperatingSystem[] =
#if defined(OS_MACOSX)
    "mac";
#elif defined(OS_WIN)
    "win";
#else  // OS_LINUX, etc. TODO(viettrungluu): Separate out Chrome OS and Android?
    "linux";
#endif

// Name of the Widevine CDM architecture in the component manifest.
const char kWidevineCdmArch[] =
#if defined(ARCH_CPU_X86)
    "ia32";
#elif defined(ARCH_CPU_X86_64)
    "x64";
#else  // TODO(viettrungluu): Support an ARM check?
    "???";
#endif

// If we don't have a Widevine CDM component, this is the version we claim.
const char kNullVersion[] = "0.0.0.0";

// The base directory on Windows looks like:
// <profile>\AppData\Local\Google\Chrome\User Data\WidevineCdm\.
base::FilePath GetWidevineCdmBaseDirectory() {
  base::FilePath result;
  PathService::Get(chrome::DIR_COMPONENT_WIDEVINE_CDM, &result);
  return result;
}

// Widevine CDM has the version encoded in the path so we need to enumerate the
// directories to find the full path.
// On success, |latest_dir| returns something like:
// <profile>\AppData\Local\Google\Chrome\User Data\WidevineCdm\10.3.44.555\.
// |latest_version| returns the corresponding version number. |older_dirs|
// returns directories of all older versions.
bool GetWidevineCdmDirectory(base::FilePath* latest_dir,
                             base::Version* latest_version,
                             std::vector<base::FilePath>* older_dirs) {
  base::FilePath base_dir = GetWidevineCdmBaseDirectory();
  bool found = false;
  file_util::FileEnumerator file_enumerator(
      base_dir, false, file_util::FileEnumerator::DIRECTORIES);
  for (base::FilePath path = file_enumerator.Next(); !path.value().empty();
       path = file_enumerator.Next()) {
    base::Version version(path.BaseName().MaybeAsASCII());
    if (!version.IsValid())
      continue;
    if (found) {
      if (version.CompareTo(*latest_version) > 0) {
        older_dirs->push_back(*latest_dir);
        *latest_dir = path;
        *latest_version = version;
      } else {
        older_dirs->push_back(path);
      }
    } else {
      *latest_dir = path;
      *latest_version = version;
      found = true;
    }
  }
  return found;
}

bool MakeWidevineCdmPluginInfo(const base::FilePath& path,
                               const base::Version& version,
                               content::PepperPluginInfo* plugin_info) {
  if (!version.IsValid() ||
      version.components().size() !=
          static_cast<size_t>(kWidevineCdmVersionNumComponents)) {
    return false;
  }

  plugin_info->is_internal = false;
  // Widevine CDM must run out of process.
  plugin_info->is_out_of_process = true;
  plugin_info->path = path;
  plugin_info->name = kWidevineCdmDisplayName;
  plugin_info->description = kWidevineCdmDescription;
  plugin_info->version = version.GetString();
  webkit::WebPluginMimeType widevine_cdm_mime_type(
      kWidevineCdmPluginMimeType,
      kWidevineCdmPluginExtension,
      kWidevineCdmPluginMimeTypeDescription);
  plugin_info->mime_types.push_back(widevine_cdm_mime_type);
  plugin_info->permissions = kWidevineCdmPluginPermissions;

  return true;
}

void RegisterWidevineCdmWithChrome(const base::FilePath& path,
                                   const base::Version& version) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  content::PepperPluginInfo plugin_info;
  if (!MakeWidevineCdmPluginInfo(path, version, &plugin_info))
    return;

  PluginService::GetInstance()->RegisterInternalPlugin(
      plugin_info.ToWebPluginInfo(), true);
  PluginService::GetInstance()->RefreshPlugins();
}

// Returns true if this browser is compatible with the given Widevine CDM
// manifest, with the version specified in the manifest in |version_out|.
bool CheckWidevineCdmManifest(const base::DictionaryValue& manifest,
                              base::Version* version_out) {
  std::string name;
  manifest.GetStringASCII("name", &name);

  if (name != kWidevineCdmManifestName)
    return false;

  std::string proposed_version;
  manifest.GetStringASCII("version", &proposed_version);
  base::Version version(proposed_version.c_str());
  if (!version.IsValid())
    return false;

  std::string os;
  manifest.GetStringASCII("x-widevine-cdm-os", &os);
  if (os != kWidevineCdmOperatingSystem)
    return false;

  std::string arch;
  manifest.GetStringASCII("x-widevine-cdm-arch", &arch);
  if (arch != kWidevineCdmArch)
    return false;

  *version_out = version;
  return true;
}

class WidevineCdmComponentInstaller : public ComponentInstaller {
 public:
  explicit WidevineCdmComponentInstaller(const base::Version& version);
  virtual ~WidevineCdmComponentInstaller() {}

  virtual void OnUpdateError(int error) OVERRIDE;
  virtual bool Install(const base::DictionaryValue& manifest,
                       const base::FilePath& unpack_path) OVERRIDE;

 private:
  base::Version current_version_;
};

WidevineCdmComponentInstaller::WidevineCdmComponentInstaller(
    const base::Version& version)
    : current_version_(version) {
  DCHECK(version.IsValid());
}

void WidevineCdmComponentInstaller::OnUpdateError(int error) {
  NOTREACHED() << "Widevine CDM update error: " << error;
}

bool WidevineCdmComponentInstaller::Install(
    const base::DictionaryValue& manifest,
    const base::FilePath& unpack_path) {
  base::Version version;
  if (!CheckWidevineCdmManifest(manifest, &version))
    return false;
  if (current_version_.CompareTo(version) > 0)
    return false;

  if (!file_util::PathExists(unpack_path.AppendASCII(kWidevineCdmFileName)))
    return false;

  base::FilePath adapter_source_path;
  PathService::Get(chrome::FILE_WIDEVINE_CDM_ADAPTER, &adapter_source_path);
  if (!file_util::PathExists(adapter_source_path))
    return false;

  // Passed the basic tests. Time to install it.
  base::FilePath install_path =
      GetWidevineCdmBaseDirectory().AppendASCII(version.GetString());
  if (file_util::PathExists(install_path))
    return false;
  if (!file_util::Move(unpack_path, install_path))
    return false;

  base::FilePath adapter_install_path =
      install_path.AppendASCII(kWidevineCdmAdapterFileName);
  if (!file_util::CopyFile(adapter_source_path, adapter_install_path))
    return false;

  // Installation is done. Now register the Widevine CDM with chrome.
  current_version_ = version;
  BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
      &RegisterWidevineCdmWithChrome, adapter_install_path, version));
  return true;
}

void FinishWidevineCdmUpdateRegistration(ComponentUpdateService* cus,
                                         const base::Version& version) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  CrxComponent widevine_cdm;
  widevine_cdm.name = "WidevineCdm";
  widevine_cdm.installer = new WidevineCdmComponentInstaller(version);
  widevine_cdm.version = version;
  widevine_cdm.pk_hash.assign(kSha2Hash, &kSha2Hash[sizeof(kSha2Hash)]);
  if (cus->RegisterComponent(widevine_cdm) != ComponentUpdateService::kOk) {
    NOTREACHED() << "Widevine CDM component registration failed.";
    return;
  }
}

void StartWidevineCdmUpdateRegistration(ComponentUpdateService* cus) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
  base::FilePath base_dir = GetWidevineCdmBaseDirectory();
  if (!file_util::PathExists(base_dir) &&
      !file_util::CreateDirectory(base_dir)) {
    NOTREACHED() << "Could not create Widevine CDM directory.";
    return;
  }

  base::FilePath latest_dir;
  base::Version version(kNullVersion);
  std::vector<base::FilePath> older_dirs;

  if (GetWidevineCdmDirectory(&latest_dir, &version, &older_dirs)) {
    base::FilePath adpater_path =
        latest_dir.AppendASCII(kWidevineCdmAdapterFileName);
    base::FilePath cdm_path = latest_dir.AppendASCII(kWidevineCdmFileName);

    if (file_util::PathExists(adapter_path) &&
        file_util::PathExists(cdm_path))) {
      BrowserThread::PostTask(
          BrowserThread::UI, FROM_HERE,
          base::Bind(&RegisterWidevineCdmWithChrome, adpater_path, version));
    } else {
      file_util::Delete(latest_dir, true);
      version = base::Version(kNullVersion);
    }
  }

  BrowserThread::PostTask(
      BrowserThread::UI, FROM_HERE,
      base::Bind(&FinishWidevineCdmUpdateRegistration, cus, version));

  // Remove older versions of Widevine CDM.
  for (std::vector<base::FilePath>::iterator iter = older_dirs.begin();
       iter != older_dirs.end(); ++iter) {
    file_util::Delete(*iter, true);
  }
}

#endif  // defined(WIDEVINE_CDM_AVAILABLE) && defined(WIDEVINE_CDM_IS_COMPONENT)

}  // namespace

void RegisterWidevineCdmComponent(ComponentUpdateService* cus) {
#if defined(WIDEVINE_CDM_AVAILABLE) && defined(WIDEVINE_CDM_IS_COMPONENT)
  BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
                          base::Bind(&StartWidevineCdmUpdateRegistration, cus));
#endif  // defined(WIDEVINE_CDM_AVAILABLE) && defined(WIDEVINE_CDM_IS_COMPONENT)
}
<|endoftext|>