Tesseract  3.02
tesseract-ocr/viewer/svutil.cpp
Go to the documentation of this file.
00001 
00002 // File:        svutil.cpp
00003 // Description: ScrollView Utilities
00004 // Author:      Joern Wanke
00005 // Created:     Thu Nov 29 2007
00006 //
00007 // (C) Copyright 2007, Google Inc.
00008 // Licensed under the Apache License, Version 2.0 (the "License");
00009 // you may not use this file except in compliance with the License.
00010 // You may obtain a copy of the License at
00011 // http://www.apache.org/licenses/LICENSE-2.0
00012 // Unless required by applicable law or agreed to in writing, software
00013 // distributed under the License is distributed on an "AS IS" BASIS,
00014 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00015 // See the License for the specific language governing permissions and
00016 // limitations under the License.
00017 //
00019 //
00020 // SVUtil contains the SVSync and SVNetwork classes, which are used for
00021 // thread/process creation & synchronization and network connection.
00022 
00023 #include <stdio.h>
00024 #ifdef _WIN32
00025 struct addrinfo {
00026   struct sockaddr* ai_addr;
00027   int ai_addrlen;
00028   int ai_family;
00029   int ai_socktype;
00030   int ai_protocol;
00031 };
00032 #else
00033 #include <arpa/inet.h>
00034 #include <netinet/in.h>
00035 #include <pthread.h>
00036 #include <semaphore.h>
00037 #include <signal.h>
00038 #include <stdlib.h>
00039 #include <string.h>
00040 #include <netdb.h>
00041 #include <sys/socket.h>
00042 #ifdef __linux__
00043 #include <sys/prctl.h>
00044 #endif
00045 #include <unistd.h>
00046 #endif
00047 
00048 #include <cstdlib>
00049 #include <cstring>
00050 #include <iostream>
00051 #include <string>
00052 
00053 // Include automatically generated configuration file if running autoconf.
00054 #ifdef HAVE_CONFIG_H
00055 #include "config_auto.h"
00056 #endif
00057 
00058 #ifndef GRAPHICS_DISABLED
00059 
00060 #include "svutil.h"
00061 
00062 const int kBufferSize = 65536;
00063 const int kMaxMsgSize = 4096;
00064 
00065 // Signals a thread to exit.
00066 void SVSync::ExitThread() {
00067 #ifdef _WIN32
00068   // ExitThread(0);
00069 #else
00070   pthread_exit(0);
00071 #endif
00072 }
00073 
00074 // Starts a new process.
00075 void SVSync::StartProcess(const char* executable, const char* args) {
00076 #ifdef _WIN32
00077   std::string proc;
00078   proc.append(executable);
00079   proc.append(" ");
00080   proc.append(args);
00081   std::cout << "Starting " << proc << std::endl;
00082   STARTUPINFO start_info;
00083   PROCESS_INFORMATION proc_info;
00084   GetStartupInfo(&start_info);
00085   if (!CreateProcess(NULL, const_cast<char*>(proc.c_str()), NULL, NULL, FALSE,
00086                 CREATE_NO_WINDOW | DETACHED_PROCESS, NULL, NULL,
00087                 &start_info, &proc_info))
00088     return;
00089 #else
00090   int pid = fork();
00091   if (pid != 0) {   // The father process returns
00092   } else {
00093 #ifdef __linux__
00094     // Make sure the java process terminates on exit, since its
00095     // broken socket detection seems to be useless.
00096     prctl(PR_SET_PDEATHSIG, 2, 0, 0, 0);
00097 #endif
00098     char* mutable_args = strdup(args);
00099     int argc = 1;
00100     for (int i = 0; mutable_args[i]; ++i) {
00101       if (mutable_args[i] == ' ') {
00102         ++argc;
00103       }
00104     }
00105     char** argv = new char*[argc + 2];
00106     argv[0] = strdup(executable);
00107     argv[1] = mutable_args;
00108     argc = 2;
00109     bool inquote = false;
00110     for (int i = 0; mutable_args[i]; ++i) {
00111       if (!inquote && mutable_args[i] == ' ') {
00112         mutable_args[i] = '\0';
00113         argv[argc++] = mutable_args + i + 1;
00114       } else if (mutable_args[i] == '"') {
00115         inquote = !inquote;
00116         mutable_args[i] = ' ';
00117       }
00118     }
00119     argv[argc] = NULL;
00120     execvp(executable, argv);
00121   }
00122 #endif
00123 }
00124 
00125 SVSemaphore::SVSemaphore() {
00126 #ifdef _WIN32
00127   semaphore_ = CreateSemaphore(0, 0, 10, 0);
00128 #else
00129   sem_init(&semaphore_, 0, 0);
00130 #endif
00131 }
00132 
00133 void SVSemaphore::Signal() {
00134 #ifdef _WIN32
00135   ReleaseSemaphore(semaphore_, 1, NULL);
00136 #else
00137   sem_post(&semaphore_);
00138 #endif
00139 }
00140 
00141 void SVSemaphore::Wait() {
00142 #ifdef _WIN32
00143   WaitForSingleObject(semaphore_, INFINITE);
00144 #else
00145   sem_wait(&semaphore_);
00146 #endif
00147 }
00148 
00149 SVMutex::SVMutex() {
00150 #ifdef _WIN32
00151   mutex_ = CreateMutex(0, FALSE, 0);
00152 #else
00153   pthread_mutex_init(&mutex_, NULL);
00154 #endif
00155 }
00156 
00157 void SVMutex::Lock() {
00158 #ifdef _WIN32
00159   WaitForSingleObject(mutex_, INFINITE);
00160 #else
00161   pthread_mutex_lock(&mutex_);
00162 #endif
00163 }
00164 
00165 void SVMutex::Unlock() {
00166 #ifdef _WIN32
00167   ReleaseMutex(mutex_);
00168 #else
00169   pthread_mutex_unlock(&mutex_);
00170 #endif
00171 }
00172 
00173 // Create new thread.
00174 
00175 void SVSync::StartThread(void *(*func)(void*), void* arg) {
00176 #ifdef _WIN32
00177   LPTHREAD_START_ROUTINE f = (LPTHREAD_START_ROUTINE) func;
00178   DWORD threadid;
00179   HANDLE newthread = CreateThread(
00180   NULL,          // default security attributes
00181   0,             // use default stack size
00182   f,             // thread function
00183   arg,           // argument to thread function
00184   0,             // use default creation flags
00185   &threadid);    // returns the thread identifier
00186 #else
00187   pthread_t helper;
00188   pthread_create(&helper, NULL, func, arg);
00189 #endif
00190 }
00191 
00192 // Place a message in the message buffer (and flush it).
00193 void SVNetwork::Send(const char* msg) {
00194   mutex_send_->Lock();
00195   msg_buffer_out_.append(msg);
00196   mutex_send_->Unlock();
00197 }
00198 
00199 // Send the whole buffer.
00200 void SVNetwork::Flush() {
00201   mutex_send_->Lock();
00202   while (msg_buffer_out_.size() > 0) {
00203     int i = send(stream_, msg_buffer_out_.c_str(), msg_buffer_out_.length(), 0);
00204     msg_buffer_out_.erase(0, i);
00205   }
00206   mutex_send_->Unlock();
00207 }
00208 
00209 // Receive a message from the server.
00210 // This will always return one line of char* (denoted by \n).
00211 char* SVNetwork::Receive() {
00212   char* result = NULL;
00213 #ifdef _WIN32
00214   if (has_content) { result = strtok (NULL, "\n"); }
00215 #else
00216   if (buffer_ptr_ != NULL) { result = strtok_r(NULL, "\n", &buffer_ptr_); }
00217 #endif
00218 
00219   // This means there is something left in the buffer and we return it.
00220   if (result != NULL) { return result;
00221   // Otherwise, we read from the stream_.
00222   } else {
00223     buffer_ptr_ = NULL;
00224     has_content = false;
00225 
00226     // The timeout length is not really important since we are looping anyway
00227     // until a new message is delivered.
00228     struct timeval tv;
00229     tv.tv_sec = 10;
00230     tv.tv_usec = 0;
00231 
00232     // Set the flags to return when the stream_ is ready to be read.
00233     fd_set readfds;
00234     FD_ZERO(&readfds);
00235     FD_SET(stream_, &readfds);
00236 
00237     int i = select(stream_+1, &readfds, NULL, NULL, &tv);
00238 
00239     // The stream_ died.
00240     if (i == 0) { return NULL; }
00241 
00242     // Read the message buffer.
00243     i = recv(stream_, msg_buffer_in_, kMaxMsgSize, 0);
00244 
00245     // Server quit (0) or error (-1).
00246     if (i <= 0) { return NULL; }
00247     msg_buffer_in_[i] = '\0';
00248     has_content = true;
00249 #ifdef _WIN32
00250     return strtok(msg_buffer_in_, "\n");
00251 #else
00252     // Setup a new string tokenizer.
00253     return strtok_r(msg_buffer_in_, "\n", &buffer_ptr_);
00254 #endif
00255   }
00256 }
00257 
00258 // Close the connection to the server.
00259 void SVNetwork::Close() {
00260 #ifdef _WIN32
00261   closesocket(stream_);
00262 #else
00263   close(stream_);
00264 #endif
00265 }
00266 
00267 
00268 // The program to invoke to start ScrollView
00269 static const char* ScrollViewProg() {
00270 #ifdef _WIN32
00271   const char* prog = "java -Xms512m -Xmx1024m";
00272 #else
00273   const char* prog = "sh";
00274 #endif
00275   return prog;
00276 }
00277 
00278 
00279 // The arguments to the program to invoke to start ScrollView
00280 static std::string ScrollViewCommand(std::string scrollview_path) {
00281   // The following ugly ifdef is to enable the output of the java runtime
00282   // to be sent down a black hole on non-windows to ignore all the
00283   // exceptions in piccolo. Ideally piccolo would be debugged to make
00284   // this unnecessary.
00285   // Also the path has to be separated by ; on windows and : otherwise.
00286 #ifdef _WIN32
00287   const char* cmd_template = "-Djava.library.path=%s -cp %s/ScrollView.jar;"
00288       "%s/piccolo-1.2.jar;%s/piccolox-1.2.jar"
00289       " com.google.scrollview.ScrollView";
00290 #else
00291   const char* cmd_template = "-c \"trap 'kill %1' 0 1 2 ; java "
00292       "-Xms1024m -Xmx2048m -Djava.library.path=%s -cp %s/ScrollView.jar:"
00293       "%s/piccolo-1.2.jar:%s/piccolox-1.2.jar"
00294       " com.google.scrollview.ScrollView"
00295       " >/dev/null 2>&1 & wait\"";
00296 #endif
00297   int cmdlen = strlen(cmd_template) + 4*strlen(scrollview_path.c_str()) + 1;
00298   char* cmd = new char[cmdlen];
00299   const char* sv_path = scrollview_path.c_str();
00300   snprintf(cmd, cmdlen, cmd_template, sv_path, sv_path, sv_path, sv_path);
00301   std::string command(cmd);
00302   delete [] cmd;
00303   return command;
00304 }
00305 
00306 
00307 // Platform-independent freeaddrinfo()
00308 static void FreeAddrInfo(struct addrinfo* addr_info) {
00309   #if defined(__linux__)
00310   freeaddrinfo(addr_info);
00311   #else
00312   delete addr_info->ai_addr;
00313   delete addr_info;
00314   #endif
00315 }
00316 
00317 
00318 // Non-linux version of getaddrinfo()
00319 #if !defined(__linux__)
00320 static int GetAddrInfoNonLinux(const char* hostname, int port,
00321                                struct addrinfo** addr_info) {
00322 // Get the host data depending on the OS.
00323   struct sockaddr_in* address;
00324   *addr_info = new struct addrinfo;
00325   memset(*addr_info, 0, sizeof(struct addrinfo));
00326   address = new struct sockaddr_in;
00327   memset(address, 0, sizeof(struct sockaddr_in));
00328 
00329   (*addr_info)->ai_addr = (struct sockaddr*) address;
00330   (*addr_info)->ai_addrlen = sizeof(struct sockaddr);
00331   (*addr_info)->ai_family = AF_INET;
00332   (*addr_info)->ai_socktype = SOCK_STREAM;
00333 
00334   struct hostent *name;
00335 #ifdef _WIN32
00336   WSADATA wsaData;
00337   WSAStartup(MAKEWORD(1, 1), &wsaData);
00338   name = gethostbyname(hostname);
00339 #else
00340   name = gethostbyname(hostname);
00341 #endif
00342 
00343   if (name == NULL) {
00344     FreeAddrInfo(*addr_info);
00345     *addr_info = NULL;
00346     return -1;
00347   }
00348 
00349   // Fill in the appropriate variables to be able to connect to the server.
00350   address->sin_family = name->h_addrtype;
00351   memcpy((char *) &address->sin_addr.s_addr,
00352          name->h_addr_list[0], name->h_length);
00353   address->sin_port = htons(port);
00354   return 0;
00355 }
00356 #endif
00357 
00358 
00359 // Platform independent version of getaddrinfo()
00360 //   Given a hostname:port, produce an addrinfo struct
00361 static int GetAddrInfo(const char* hostname, int port,
00362                        struct addrinfo** address) {
00363 #if defined(__linux__)
00364   char port_str[40];
00365   snprintf(port_str, 40, "%d", port);
00366   return getaddrinfo(hostname, port_str, NULL, address);
00367 #else
00368   return GetAddrInfoNonLinux(hostname, port, address);
00369 #endif
00370 }
00371 
00372 
00373 // Set up a connection to a ScrollView on hostname:port.
00374 SVNetwork::SVNetwork(const char* hostname, int port) {
00375   mutex_send_ = new SVMutex();
00376   msg_buffer_in_ = new char[kMaxMsgSize + 1];
00377   msg_buffer_in_[0] = '\0';
00378 
00379   has_content = false;
00380   buffer_ptr_ = NULL;
00381 
00382   struct addrinfo *addr_info = NULL;
00383 
00384   if (GetAddrInfo(hostname, port, &addr_info) != 0) {
00385     std::cerr << "Error resolving name for ScrollView host "
00386               << std::string(hostname) << ":" << port << std::endl;
00387   }
00388 
00389   stream_ = socket(addr_info->ai_family, addr_info->ai_socktype,
00390                    addr_info->ai_protocol);
00391 
00392   // If server is not there, we will start a new server as local child process.
00393   if (connect(stream_, addr_info->ai_addr, addr_info->ai_addrlen) < 0) {
00394     const char* scrollview_path = getenv("SCROLLVIEW_PATH");
00395     if (scrollview_path == NULL) {
00396 #ifdef SCROLLVIEW_PATH
00397 #define _STR(a) #a
00398 #define _XSTR(a) _STR(a)
00399       scrollview_path = _XSTR(SCROLLVIEW_PATH);
00400 #undef _XSTR
00401 #undef _STR
00402 #else
00403       scrollview_path = ".";
00404 #endif
00405     }
00406     const char *prog = ScrollViewProg();
00407     std::string command = ScrollViewCommand(scrollview_path);
00408     SVSync::StartProcess(prog, command.c_str());
00409 
00410     // Wait for server to show up.
00411     // Note: There is no exception handling in case the server never turns up.
00412     while (connect(stream_, (struct sockaddr *) addr_info->ai_addr,
00413                    addr_info->ai_addrlen) < 0) {
00414       std::cout << "ScrollView: Waiting for server...\n";
00415 #ifdef _WIN32
00416       Sleep(1000);
00417 #else
00418       sleep(1);
00419 #endif
00420     }
00421   }
00422   FreeAddrInfo(addr_info);
00423 }
00424 
00425 SVNetwork::~SVNetwork() {
00426   delete[] msg_buffer_in_;
00427   delete mutex_send_;
00428 }
00429 
00430 #endif  // GRAPHICS_DISABLED