test: 增加ocr接口的单元测试
Description: 增加ocr接口的单元测试 Log: no Change-Id: Ie78bb8f8d2def33ce441857daef52bdc4efa5650
This commit is contained in:
parent
c2f16bd20e
commit
facb87f672
280
3rdparty/stub_linux/addr_any.h
vendored
Executable file
280
3rdparty/stub_linux/addr_any.h
vendored
Executable file
|
@ -0,0 +1,280 @@
|
|||
#ifndef __ADDR_ANY_H__
|
||||
#define __ADDR_ANY_H__
|
||||
|
||||
|
||||
//linux
|
||||
#include <regex.h>
|
||||
#include <cxxabi.h>
|
||||
//c
|
||||
#include <cinttypes>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
|
||||
//c++
|
||||
#include <string>
|
||||
#include <map>
|
||||
//project
|
||||
#include "elfio.hpp"
|
||||
|
||||
|
||||
|
||||
class AddrAny
|
||||
{
|
||||
public:
|
||||
AddrAny()
|
||||
{
|
||||
m_init = get_exe_pathname(m_fullname);
|
||||
m_baseaddr = 0;
|
||||
}
|
||||
AddrAny(std::string libname)
|
||||
{
|
||||
m_init = get_lib_pathname_and_baseaddr(libname, m_fullname, m_baseaddr);
|
||||
}
|
||||
|
||||
int get_local_func_addr_symtab(std::string func_name_regex_str, std::map<std::string,void*>& result)
|
||||
{
|
||||
return get_func_addr(SHT_SYMTAB, STB_LOCAL, func_name_regex_str, result);
|
||||
}
|
||||
int get_global_func_addr_symtab(std::string func_name_regex_str, std::map<std::string,void*>& result)
|
||||
{
|
||||
return get_func_addr(SHT_SYMTAB, STB_GLOBAL, func_name_regex_str, result);
|
||||
}
|
||||
int get_weak_func_addr_symtab(std::string func_name_regex_str, std::map<std::string,void*>& result)
|
||||
{
|
||||
return get_func_addr(SHT_SYMTAB, STB_WEAK, func_name_regex_str, result);
|
||||
}
|
||||
|
||||
int get_global_func_addr_dynsym( std::string func_name_regex_str, std::map<std::string,void*>& result)
|
||||
{
|
||||
return get_func_addr(SHT_DYNSYM, STB_GLOBAL, func_name_regex_str, result);
|
||||
}
|
||||
int get_weak_func_addr_dynsym(std::string func_name_regex_str, std::map<std::string,void*>& result)
|
||||
{
|
||||
return get_func_addr(SHT_DYNSYM, STB_WEAK, func_name_regex_str, result);
|
||||
}
|
||||
|
||||
private:
|
||||
bool demangle(std::string& s, std::string& name) {
|
||||
int status;
|
||||
char* pname = abi::__cxa_demangle(s.c_str(), 0, 0, &status);
|
||||
if (status != 0)
|
||||
{
|
||||
switch(status)
|
||||
{
|
||||
case -1: name = "memory allocation error"; break;
|
||||
case -2: name = "invalid name given"; break;
|
||||
case -3: name = "internal error: __cxa_demangle: invalid argument"; break;
|
||||
default: name = "unknown error occured"; break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
name = pname;
|
||||
free(pname);
|
||||
return true;
|
||||
}
|
||||
bool get_exe_pathname( std::string& name)
|
||||
{
|
||||
char line[512];
|
||||
FILE *fp;
|
||||
uintptr_t base_addr;
|
||||
char perm[5];
|
||||
unsigned long offset;
|
||||
int pathname_pos;
|
||||
char *pathname;
|
||||
size_t pathname_len;
|
||||
int match = 0;
|
||||
|
||||
if(NULL == (fp = fopen("/proc/self/maps", "r")))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
while(fgets(line, sizeof(line), fp))
|
||||
{
|
||||
if(sscanf(line, "%" PRIxPTR "-%*lx %4s %lx %*x:%*x %*d%n", &base_addr, perm, &offset, &pathname_pos) != 3) continue;
|
||||
|
||||
if(0 != offset) continue;
|
||||
|
||||
//get pathname
|
||||
while(isspace(line[pathname_pos]) && pathname_pos < (int)(sizeof(line) - 1))
|
||||
pathname_pos += 1;
|
||||
if(pathname_pos >= (int)(sizeof(line) - 1)) continue;
|
||||
pathname = line + pathname_pos;
|
||||
pathname_len = strlen(pathname);
|
||||
if(0 == pathname_len) continue;
|
||||
if(pathname[pathname_len - 1] == '\n')
|
||||
{
|
||||
pathname[pathname_len - 1] = '\0';
|
||||
pathname_len -= 1;
|
||||
}
|
||||
if(0 == pathname_len) continue;
|
||||
if('[' == pathname[0]) continue;
|
||||
|
||||
name = pathname;
|
||||
match = 1;
|
||||
break;
|
||||
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
if(0 == match)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool get_lib_pathname_and_baseaddr(std::string pathname_regex_str, std::string& name, unsigned long& addr)
|
||||
{
|
||||
char line[512];
|
||||
FILE *fp;
|
||||
uintptr_t base_addr;
|
||||
char perm[5];
|
||||
unsigned long offset;
|
||||
int pathname_pos;
|
||||
char *pathname;
|
||||
size_t pathname_len;
|
||||
int match;
|
||||
regex_t pathname_regex;
|
||||
|
||||
regcomp(&pathname_regex, pathname_regex_str.c_str(), 0);
|
||||
|
||||
if(NULL == (fp = fopen("/proc/self/maps", "r")))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
while(fgets(line, sizeof(line), fp))
|
||||
{
|
||||
if(sscanf(line, "%" PRIxPTR "-%*lx %4s %lx %*x:%*x %*d%n", &base_addr, perm, &offset, &pathname_pos) != 3) continue;
|
||||
|
||||
//check permission
|
||||
if(perm[0] != 'r') continue;
|
||||
if(perm[3] != 'p') continue; //do not touch the shared memory
|
||||
|
||||
//check offset
|
||||
//
|
||||
//We are trying to find ELF header in memory.
|
||||
//It can only be found at the beginning of a mapped memory regions
|
||||
//whose offset is 0.
|
||||
if(0 != offset) continue;
|
||||
|
||||
//get pathname
|
||||
while(isspace(line[pathname_pos]) && pathname_pos < (int)(sizeof(line) - 1))
|
||||
pathname_pos += 1;
|
||||
if(pathname_pos >= (int)(sizeof(line) - 1)) continue;
|
||||
pathname = line + pathname_pos;
|
||||
pathname_len = strlen(pathname);
|
||||
if(0 == pathname_len) continue;
|
||||
if(pathname[pathname_len - 1] == '\n')
|
||||
{
|
||||
pathname[pathname_len - 1] = '\0';
|
||||
pathname_len -= 1;
|
||||
}
|
||||
if(0 == pathname_len) continue;
|
||||
if('[' == pathname[0]) continue;
|
||||
|
||||
//check pathname
|
||||
//if we need to hook this elf?
|
||||
match = 0;
|
||||
if(0 == regexec(&pathname_regex, pathname, 0, NULL, 0))
|
||||
{
|
||||
match = 1;
|
||||
name = pathname;
|
||||
addr = (unsigned long)base_addr;
|
||||
break;
|
||||
}
|
||||
if(0 == match) continue;
|
||||
|
||||
}
|
||||
fclose(fp);
|
||||
if(0 == match)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int get_func_addr(unsigned int ttype, unsigned int stype, std::string& func_name_regex_str, std::map<std::string,void*>& result)
|
||||
{
|
||||
// Create an elfio reader
|
||||
ELFIO::elfio reader;
|
||||
int count = 0;
|
||||
regex_t pathname_regex;
|
||||
|
||||
if(!m_init)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
regcomp(&pathname_regex, func_name_regex_str.c_str(), 0);
|
||||
// Load ELF data
|
||||
if(!reader.load(m_fullname.c_str()))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
ELFIO::Elf_Half sec_num = reader.sections.size();
|
||||
for(int i = 0; i < sec_num; ++i)
|
||||
{
|
||||
ELFIO::section* psec = reader.sections[i];
|
||||
// Check section type
|
||||
if(psec->get_type() == ttype)
|
||||
{
|
||||
const ELFIO::symbol_section_accessor symbols( reader, psec );
|
||||
for ( unsigned int j = 0; j < symbols.get_symbols_num(); ++j )
|
||||
{
|
||||
std::string name;
|
||||
std::string name_mangle;
|
||||
ELFIO::Elf64_Addr value;
|
||||
ELFIO::Elf_Xword size;
|
||||
unsigned char bind;
|
||||
unsigned char type;
|
||||
ELFIO::Elf_Half section_index;
|
||||
unsigned char other;
|
||||
|
||||
// Read symbol properties
|
||||
symbols.get_symbol( j, name, value, size, bind, type, section_index, other );
|
||||
if(type == STT_FUNC && bind == stype)
|
||||
{
|
||||
bool ret = demangle(name,name_mangle);
|
||||
if(ret == true)
|
||||
{
|
||||
if (0 == regexec(&pathname_regex, name_mangle.c_str(), 0, NULL, 0))
|
||||
{
|
||||
result.insert ( std::pair<std::string,void *>(name_mangle,(void*)(value + m_baseaddr)));
|
||||
count++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (0 == regexec(&pathname_regex, name.c_str(), 0, NULL, 0))
|
||||
{
|
||||
result.insert ( std::pair<std::string,void *>(name,(void*)(value + m_baseaddr)));
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
private:
|
||||
bool m_init;
|
||||
std::string m_name;
|
||||
std::string m_fullname;
|
||||
unsigned long m_baseaddr;
|
||||
|
||||
};
|
||||
#endif
|
177
3rdparty/stub_linux/addr_pri.h
vendored
Executable file
177
3rdparty/stub_linux/addr_pri.h
vendored
Executable file
|
@ -0,0 +1,177 @@
|
|||
#ifndef __ADDR_PRI_H__
|
||||
#define __ADDR_PRI_H__
|
||||
|
||||
|
||||
#include <utility>
|
||||
#include <type_traits>
|
||||
|
||||
|
||||
|
||||
//base on C++11
|
||||
|
||||
/**********************************************************
|
||||
access private function
|
||||
**********************************************************/
|
||||
|
||||
|
||||
namespace std {
|
||||
template <bool B, class T = void>
|
||||
using enable_if_t = typename enable_if<B, T>::type;
|
||||
template <class T>
|
||||
using remove_reference_t = typename remove_reference<T>::type;
|
||||
} // std
|
||||
|
||||
// Unnamed namespace is used to avoid duplicate symbols if the macros are used
|
||||
namespace {
|
||||
namespace private_access_detail {
|
||||
|
||||
// @tparam TagType, used to declare different "get" funciton overloads for
|
||||
// different members/statics
|
||||
template <typename PtrType, PtrType PtrValue, typename TagType>
|
||||
struct private_access {
|
||||
// Normal lookup cannot find in-class defined (inline) friend functions.
|
||||
friend PtrType get(TagType) { return PtrValue; }
|
||||
};
|
||||
|
||||
} // namespace private_access_detail
|
||||
} // namespace
|
||||
|
||||
// Used macro naming conventions:
|
||||
// The "namespace" of this macro library is PRIVATE_ACCESS, i.e. all
|
||||
// macro here has this prefix.
|
||||
// All implementation macro, which are not meant to be used directly have the
|
||||
// PRIVATE_ACCESS_DETAIL prefix.
|
||||
// Some macros have the ABCD_IMPL form, which means they contain the
|
||||
// implementation details for the specific ABCD macro.
|
||||
|
||||
#define PRIVATE_ACCESS_DETAIL_CONCATENATE_IMPL(x, y) x##y
|
||||
#define PRIVATE_ACCESS_DETAIL_CONCATENATE(x, y) \
|
||||
PRIVATE_ACCESS_DETAIL_CONCATENATE_IMPL(x, y)
|
||||
|
||||
// @param PtrTypeKind E.g if we have "class A", then it can be "A::*" in case of
|
||||
// members, or it can be "*" in case of statics.
|
||||
#define PRIVATE_ACCESS_DETAIL_ACCESS_PRIVATE(Tag, Class, Type, Name, \
|
||||
PtrTypeKind) \
|
||||
namespace { \
|
||||
namespace private_access_detail { \
|
||||
/* Tag type, used to declare different get funcitons for different \
|
||||
* members \
|
||||
*/ \
|
||||
struct Tag {}; \
|
||||
/* Explicit instantiation */ \
|
||||
template struct private_access<decltype(&Class::Name), &Class::Name, \
|
||||
Tag>; \
|
||||
/* We can build the PtrType only with two aliases */ \
|
||||
/* E.g. using PtrType = int(int) *; would be illformed */ \
|
||||
using PRIVATE_ACCESS_DETAIL_CONCATENATE(Alias_, Tag) = Type; \
|
||||
using PRIVATE_ACCESS_DETAIL_CONCATENATE(PtrType_, Tag) = \
|
||||
PRIVATE_ACCESS_DETAIL_CONCATENATE(Alias_, Tag) PtrTypeKind; \
|
||||
/* Declare the friend function, now it is visible in namespace scope. \
|
||||
* Note, \
|
||||
* we could declare it inside the Tag type too, in that case ADL would \
|
||||
* find \
|
||||
* the declaration. By choosing to declare it here, the Tag type remains \
|
||||
* a \
|
||||
* simple tag type, it has no other responsibilities. */ \
|
||||
PRIVATE_ACCESS_DETAIL_CONCATENATE(PtrType_, Tag) get(Tag); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define PRIVATE_ACCESS_DETAIL_ACCESS_PRIVATE_FIELD(Tag, Class, Type, Name) \
|
||||
PRIVATE_ACCESS_DETAIL_ACCESS_PRIVATE(Tag, Class, Type, Name, Class::*) \
|
||||
namespace { \
|
||||
namespace access_private_field { \
|
||||
Type &Class##Name(Class &&t) { return t.*get(private_access_detail::Tag{}); } \
|
||||
Type &Class##Name(Class &t) { return t.*get(private_access_detail::Tag{}); } \
|
||||
/* The following usings are here to avoid duplicate const qualifier \
|
||||
* warnings \
|
||||
*/ \
|
||||
using PRIVATE_ACCESS_DETAIL_CONCATENATE(X, Tag) = Type; \
|
||||
using PRIVATE_ACCESS_DETAIL_CONCATENATE(Y, Tag) = \
|
||||
const PRIVATE_ACCESS_DETAIL_CONCATENATE(X, Tag); \
|
||||
PRIVATE_ACCESS_DETAIL_CONCATENATE(Y, Tag) & Class##Name(const Class &t) {\
|
||||
return t.*get(private_access_detail::Tag{}); \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
#define PRIVATE_ACCESS_DETAIL_ACCESS_PRIVATE_FUN(Tag, Class, Type, Name) \
|
||||
PRIVATE_ACCESS_DETAIL_ACCESS_PRIVATE(Tag, Class, Type, Name, Class::*) \
|
||||
namespace { \
|
||||
namespace call_private_fun { \
|
||||
/* We do perfect forwarding, but we want to restrict the overload set \
|
||||
* only for objects which have the type Class. */ \
|
||||
template <typename Obj, \
|
||||
std::enable_if_t<std::is_same<std::remove_reference_t<Obj>, \
|
||||
Class>::value> * = nullptr, \
|
||||
typename... Args> \
|
||||
auto Class##Name(Obj &&o, Args &&... args) -> decltype( \
|
||||
(std::forward<Obj>(o).* \
|
||||
get(private_access_detail::Tag{}))(std::forward<Args>(args)...)) { \
|
||||
return (std::forward<Obj>(o).*get(private_access_detail::Tag{}))( \
|
||||
std::forward<Args>(args)...); \
|
||||
} \
|
||||
} \
|
||||
namespace get_private_fun { \
|
||||
auto Class##Name() -> decltype( \
|
||||
get(private_access_detail::Tag{})) { \
|
||||
return (get(private_access_detail::Tag{})); \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
#define PRIVATE_ACCESS_DETAIL_ACCESS_PRIVATE_STATIC_FIELD(Tag, Class, Type, \
|
||||
Name) \
|
||||
PRIVATE_ACCESS_DETAIL_ACCESS_PRIVATE(Tag, Class, Type, Name, *) \
|
||||
namespace { \
|
||||
namespace access_private_static_field { \
|
||||
namespace Class { \
|
||||
Type &Class##Name() { return *get(private_access_detail::Tag{}); } \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
#define PRIVATE_ACCESS_DETAIL_ACCESS_PRIVATE_STATIC_FUN(Tag, Class, Type, \
|
||||
Name) \
|
||||
PRIVATE_ACCESS_DETAIL_ACCESS_PRIVATE(Tag, Class, Type, Name, *) \
|
||||
namespace { \
|
||||
namespace call_private_static_fun { \
|
||||
namespace Class { \
|
||||
template <typename... Args> \
|
||||
auto Class##Name(Args &&... args) -> decltype( \
|
||||
get(private_access_detail::Tag{})(std::forward<Args>(args)...)) { \
|
||||
return get(private_access_detail::Tag{})( \
|
||||
std::forward<Args>(args)...); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
namespace get_private_static_fun { \
|
||||
namespace Class { \
|
||||
auto Class##Name() -> decltype(get(private_access_detail::Tag{})) { \
|
||||
return get(private_access_detail::Tag{}); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
#define PRIVATE_ACCESS_DETAIL_UNIQUE_TAG \
|
||||
PRIVATE_ACCESS_DETAIL_CONCATENATE(PrivateAccessTag, __COUNTER__)
|
||||
|
||||
#define ACCESS_PRIVATE_FIELD(Class, Type, Name) \
|
||||
PRIVATE_ACCESS_DETAIL_ACCESS_PRIVATE_FIELD(PRIVATE_ACCESS_DETAIL_UNIQUE_TAG, \
|
||||
Class, Type, Name)
|
||||
|
||||
#define ACCESS_PRIVATE_FUN(Class, Type, Name) \
|
||||
PRIVATE_ACCESS_DETAIL_ACCESS_PRIVATE_FUN(PRIVATE_ACCESS_DETAIL_UNIQUE_TAG, \
|
||||
Class, Type, Name)
|
||||
|
||||
#define ACCESS_PRIVATE_STATIC_FIELD(Class, Type, Name) \
|
||||
Type Class::Name; \
|
||||
PRIVATE_ACCESS_DETAIL_ACCESS_PRIVATE_STATIC_FIELD( \
|
||||
PRIVATE_ACCESS_DETAIL_UNIQUE_TAG, Class, Type, Name)
|
||||
|
||||
#define ACCESS_PRIVATE_STATIC_FUN(Class, Type, Name) \
|
||||
PRIVATE_ACCESS_DETAIL_ACCESS_PRIVATE_STATIC_FUN( \
|
||||
PRIVATE_ACCESS_DETAIL_UNIQUE_TAG, Class, Type, Name)
|
||||
|
||||
#endif
|
4888
3rdparty/stub_linux/elfio.hpp
vendored
Executable file
4888
3rdparty/stub_linux/elfio.hpp
vendored
Executable file
File diff suppressed because it is too large
Load Diff
281
3rdparty/stub_linux/stub.h
vendored
Executable file
281
3rdparty/stub_linux/stub.h
vendored
Executable file
|
@ -0,0 +1,281 @@
|
|||
#ifndef __STUB_H__
|
||||
#define __STUB_H__
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
//windows
|
||||
#include <windows.h>
|
||||
#else
|
||||
//linux
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
//c
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
//c++
|
||||
#include <map>
|
||||
|
||||
|
||||
#define ADDR(CLASS_NAME,MEMBER_NAME) (&CLASS_NAME::MEMBER_NAME)
|
||||
|
||||
/**********************************************************
|
||||
replace function
|
||||
**********************************************************/
|
||||
|
||||
|
||||
#if defined(__aarch64__) || defined(_M_ARM64)
|
||||
#define CODESIZE 16U
|
||||
#define CODESIZE_MIN 16U
|
||||
#define CODESIZE_MAX CODESIZE
|
||||
// ldr x9, +8
|
||||
// br x9
|
||||
// addr
|
||||
#define REPLACE_FAR(t, fn, fn_stub)\
|
||||
((uint32_t*)fn)[0] = 0x58000040 | 9;\
|
||||
((uint32_t*)fn)[1] = 0xd61f0120 | (9 << 5);\
|
||||
*(long long *)(fn + 8) = (long long )fn_stub;
|
||||
#define REPLACE_NEAR(t, fn, fn_stub) REPLACE_FAR(t, fn, fn_stub)
|
||||
#elif defined(__arm__) || defined(_M_ARM)
|
||||
#define CODESIZE 8U
|
||||
#define CODESIZE_MIN 8U
|
||||
#define CODESIZE_MAX CODESIZE
|
||||
// ldr pc, [pc, #-4]
|
||||
#define REPLACE_FAR(t, fn, fn_stub)\
|
||||
((uint32_t*)fn)[0] = 0xe51ff004;\
|
||||
((uint32_t*)fn)[1] = (uint32_t)fn_stub;
|
||||
#define REPLACE_NEAR(t, fn, fn_stub) REPLACE_FAR(t, fn, fn_stub)
|
||||
#elif defined(__thumb__) || defined(_M_THUMB)
|
||||
#error "Thumb is not supported"
|
||||
#else //__i386__ _x86_64__
|
||||
#define CODESIZE 13U
|
||||
#define CODESIZE_MIN 5U
|
||||
#define CODESIZE_MAX CODESIZE
|
||||
//13 byte(jmp m16:64)
|
||||
//movabs $0x102030405060708,%r11
|
||||
//jmpq *%r11
|
||||
#define REPLACE_FAR(t, fn, fn_stub)\
|
||||
*fn = 0x49;\
|
||||
*(fn + 1) = 0xbb;\
|
||||
*(long long *)(fn + 2) = (long long)fn_stub;\
|
||||
*(fn + 10) = 0x41;\
|
||||
*(fn + 11) = 0xff;\
|
||||
*(fn + 12) = 0xe3;
|
||||
|
||||
//5 byte(jmp rel32)
|
||||
#define REPLACE_NEAR(t, fn, fn_stub)\
|
||||
*fn = 0xE9;\
|
||||
*(int *)(fn + 1) = (int)(fn_stub - fn - CODESIZE_MIN);
|
||||
#endif
|
||||
|
||||
struct func_stub
|
||||
{
|
||||
char *fn;
|
||||
unsigned char code_buf[CODESIZE];
|
||||
bool far_jmp;
|
||||
};
|
||||
|
||||
class Stub
|
||||
{
|
||||
public:
|
||||
Stub()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
SYSTEM_INFO sys_info;
|
||||
GetSystemInfo(&sys_info);
|
||||
m_pagesize = sys_info.dwPageSize;
|
||||
#else
|
||||
m_pagesize = sysconf(_SC_PAGE_SIZE);
|
||||
#endif
|
||||
|
||||
if (m_pagesize < 0)
|
||||
{
|
||||
m_pagesize = 4096;
|
||||
}
|
||||
}
|
||||
~Stub()
|
||||
{
|
||||
std::map<char*,func_stub*>::iterator iter;
|
||||
struct func_stub *pstub;
|
||||
for(iter=m_result.begin(); iter != m_result.end(); iter++)
|
||||
{
|
||||
pstub = iter->second;
|
||||
#ifdef _WIN32
|
||||
DWORD lpflOldProtect;
|
||||
if(0 != VirtualProtect(pageof(pstub->fn), m_pagesize * 2, PAGE_EXECUTE_READWRITE, &lpflOldProtect))
|
||||
#else
|
||||
if (0 == mprotect(pageof(pstub->fn), m_pagesize * 2, PROT_READ | PROT_WRITE | PROT_EXEC))
|
||||
#endif
|
||||
{
|
||||
|
||||
if(pstub->far_jmp)
|
||||
{
|
||||
std::memcpy(pstub->fn, pstub->code_buf, CODESIZE_MAX);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::memcpy(pstub->fn, pstub->code_buf, CODESIZE_MIN);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
VirtualProtect(pageof(pstub->fn), m_pagesize * 2, PAGE_EXECUTE_READ, &lpflOldProtect);
|
||||
#else
|
||||
mprotect(pageof(pstub->fn), m_pagesize * 2, PROT_READ | PROT_EXEC);
|
||||
#endif
|
||||
}
|
||||
|
||||
iter->second = NULL;
|
||||
delete pstub;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
template<typename T,typename S>
|
||||
void set(T addr, S addr_stub)
|
||||
{
|
||||
char * fn;
|
||||
char * fn_stub;
|
||||
fn = addrof(addr);
|
||||
fn_stub = addrof(addr_stub);
|
||||
struct func_stub *pstub;
|
||||
pstub = new func_stub;
|
||||
//start
|
||||
pstub->fn = fn;
|
||||
|
||||
if(distanceof(fn, fn_stub))
|
||||
{
|
||||
pstub->far_jmp = true;
|
||||
std::memcpy(pstub->code_buf, fn, CODESIZE_MAX);
|
||||
}
|
||||
else
|
||||
{
|
||||
pstub->far_jmp = false;
|
||||
std::memcpy(pstub->code_buf, fn, CODESIZE_MIN);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
DWORD lpflOldProtect;
|
||||
if(0 == VirtualProtect(pageof(pstub->fn), m_pagesize * 2, PAGE_EXECUTE_READWRITE, &lpflOldProtect))
|
||||
#else
|
||||
if (-1 == mprotect(pageof(pstub->fn), m_pagesize * 2, PROT_READ | PROT_WRITE | PROT_EXEC))
|
||||
#endif
|
||||
{
|
||||
throw("stub set memory protect to w+r+x faild");
|
||||
}
|
||||
|
||||
if(pstub->far_jmp)
|
||||
{
|
||||
REPLACE_FAR(this, fn, fn_stub);
|
||||
}
|
||||
else
|
||||
{
|
||||
REPLACE_NEAR(this, fn, fn_stub);
|
||||
}
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
if(0 == VirtualProtect(pageof(pstub->fn), m_pagesize * 2, PAGE_EXECUTE_READ, &lpflOldProtect))
|
||||
#else
|
||||
if (-1 == mprotect(pageof(pstub->fn), m_pagesize * 2, PROT_READ | PROT_EXEC))
|
||||
#endif
|
||||
{
|
||||
throw("stub set memory protect to r+x failed");
|
||||
}
|
||||
m_result.insert(std::pair<char*,func_stub*>(fn,pstub));
|
||||
return;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void reset(T addr)
|
||||
{
|
||||
char * fn;
|
||||
fn = addrof(addr);
|
||||
|
||||
std::map<char*,func_stub*>::iterator iter = m_result.find(fn);
|
||||
|
||||
if (iter == m_result.end())
|
||||
{
|
||||
return;
|
||||
}
|
||||
struct func_stub *pstub;
|
||||
pstub = iter->second;
|
||||
|
||||
#ifdef _WIN32
|
||||
DWORD lpflOldProtect;
|
||||
if(0 == VirtualProtect(pageof(pstub->fn), m_pagesize * 2, PAGE_EXECUTE_READWRITE, &lpflOldProtect))
|
||||
#else
|
||||
if (-1 == mprotect(pageof(pstub->fn), m_pagesize * 2, PROT_READ | PROT_WRITE | PROT_EXEC))
|
||||
#endif
|
||||
{
|
||||
throw("stub reset memory protect to w+r+x faild");
|
||||
}
|
||||
|
||||
if(pstub->far_jmp)
|
||||
{
|
||||
std::memcpy(pstub->fn, pstub->code_buf, CODESIZE_MAX);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::memcpy(pstub->fn, pstub->code_buf, CODESIZE_MIN);
|
||||
}
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
if(0 == VirtualProtect(pageof(pstub->fn), m_pagesize * 2, PAGE_EXECUTE_READ, &lpflOldProtect))
|
||||
#else
|
||||
if (-1 == mprotect(pageof(pstub->fn), m_pagesize * 2, PROT_READ | PROT_EXEC))
|
||||
#endif
|
||||
{
|
||||
throw("stub reset memory protect to r+x failed");
|
||||
}
|
||||
m_result.erase(iter);
|
||||
delete pstub;
|
||||
|
||||
return;
|
||||
}
|
||||
private:
|
||||
char *pageof(char* addr)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return (char *)((unsigned long long)addr & ~(m_pagesize - 1));
|
||||
#else
|
||||
return (char *)((unsigned long)addr & ~(m_pagesize - 1));
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
char* addrof(T addr)
|
||||
{
|
||||
union
|
||||
{
|
||||
T _s;
|
||||
char* _d;
|
||||
}ut;
|
||||
ut._s = addr;
|
||||
return ut._d;
|
||||
}
|
||||
|
||||
bool distanceof(char* addr, char* addr_stub)
|
||||
{
|
||||
std::ptrdiff_t diff = addr_stub >= addr ? addr_stub - addr : addr - addr_stub;
|
||||
if((sizeof(addr) > 4) && (((diff >> 31) - 1) > 0))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
#ifdef _WIN32
|
||||
//LLP64
|
||||
long long m_pagesize;
|
||||
#else
|
||||
//LP64
|
||||
long m_pagesize;
|
||||
#endif
|
||||
std::map<char*, func_stub*> m_result;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif
|
|
@ -134,6 +134,7 @@ if(DOTEST)
|
|||
include_directories(./src/service)
|
||||
include_directories(./src/tessocrutils)
|
||||
include_directories(./src/view)
|
||||
include_directories(${PROJECT_SOURCE_DIR}/3rdparty/stub_linux/)
|
||||
#需要使用tesseract源码时添加tesseract三方库文件
|
||||
# include_directories(/usr/include/leptonica)
|
||||
# include_directories(${PROJECT_SOURCE_DIR}/3rdparty/tesseract_ocr/tesseract/include)
|
||||
|
@ -156,6 +157,7 @@ if(DOTEST)
|
|||
aux_source_directory(src/view allTestSource)
|
||||
aux_source_directory(tests allTestSource)
|
||||
aux_source_directory(tests/tessocrutils allTestSource)
|
||||
aux_source_directory(${PROJECT_SOURCE_DIR}/3rdparty/stub_linux/ allTestSource)
|
||||
#需要使用tesseract源码时添加tesseract三方库文件
|
||||
# aux_source_directory(3rdparty/tesseract_ocr/tesseract/src/api allTestSource)
|
||||
# #aux_source_directory(3rdparty/tesseract_ocr/tesseract/src/arch allSource)
|
||||
|
|
|
@ -125,7 +125,7 @@ RecognitionResult TessOcrUtils::getRecogitionResult(const QString &imagePath,con
|
|||
return t_result;
|
||||
}
|
||||
//获取识别结果
|
||||
return getRecogitionResult(p_image,resultType);
|
||||
return getRecognizeResult(p_image,resultType);
|
||||
}
|
||||
|
||||
//传入待识别图片的路径,获取纯字符串的识别结果
|
||||
|
@ -171,7 +171,7 @@ RecognitionResult TessOcrUtils::getRecogitionResult(QImage *image, const ResultT
|
|||
//p_image->colormap->n;
|
||||
p_image->data = reinterpret_cast<l_uint32*>(image->bits());
|
||||
//获取识别结果
|
||||
return getRecogitionResult(p_image,resultType);
|
||||
return getRecognizeResult(p_image,resultType);
|
||||
}
|
||||
|
||||
//传入待识别图片,获取纯字符串的识别结果
|
||||
|
@ -231,7 +231,7 @@ bool TessOcrUtils::setLanguagesPath(const QString langsPath)
|
|||
}
|
||||
|
||||
//获取识别结果
|
||||
RecognitionResult TessOcrUtils::getRecogitionResult(Pix * image,ResultType resultType)
|
||||
RecognitionResult TessOcrUtils::getRecognizeResult(Pix * image,ResultType resultType)
|
||||
{
|
||||
QString errorMessage = "";
|
||||
ErrorCode errorCode = ErrorCode::UNKNOWN;
|
||||
|
|
|
@ -228,7 +228,7 @@ private :
|
|||
* @param 返回的字符串结果类型
|
||||
* @return 返回识别结果
|
||||
*/
|
||||
RecognitionResult getRecogitionResult(Pix * image,ResultType resultType);
|
||||
RecognitionResult getRecognizeResult(Pix * image,ResultType resultType);
|
||||
|
||||
/**
|
||||
* @brief 设置返回结果,内部使用
|
||||
|
|
215
tests/tessocrutils/test_tessocrutils.cpp
Normal file
215
tests/tessocrutils/test_tessocrutils.cpp
Normal file
|
@ -0,0 +1,215 @@
|
|||
/*
|
||||
|
||||
* Copyright (C) 2019 ~ 2019 Deepin Technology Co., Ltd.
|
||||
|
||||
*
|
||||
|
||||
* Author: wangcong <wangcong@uniontech.com>
|
||||
|
||||
*
|
||||
|
||||
* Maintainer: wangcong <wangcong@uniontech.com>
|
||||
|
||||
*
|
||||
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
|
||||
* any later version.
|
||||
|
||||
*
|
||||
|
||||
* This program 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 General Public License for more details.
|
||||
|
||||
*
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
#include "../../src/tessocrutils/tessocrutils.h"
|
||||
#include "stub.h"
|
||||
#include "addr_pri.h"
|
||||
#include <QDir>
|
||||
#include <QStandardPaths>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
class TessOcrUtilsTest:public testing::Test{
|
||||
|
||||
public:
|
||||
Stub stub;
|
||||
TessOcrUtils *m_tessOCrUtils = nullptr;
|
||||
virtual void SetUp() override{
|
||||
m_tessOCrUtils = TessOcrUtils::instance();
|
||||
std::cout << "start TessOcrUtilsTest" << std::endl;
|
||||
}
|
||||
|
||||
virtual void TearDown() override{
|
||||
std::cout << "end TessOcrUtilsTest" << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
ACCESS_PRIVATE_FUN(TessOcrUtils, bool(const QString), setLanguagesPath);
|
||||
ACCESS_PRIVATE_FUN(TessOcrUtils, bool(ResultType), isExistsResultType);
|
||||
ACCESS_PRIVATE_FUN(TessOcrUtils, QString(Languages), getLangStr);
|
||||
ACCESS_PRIVATE_FUN(TessOcrUtils, Languages(), getSystemLang);
|
||||
ACCESS_PRIVATE_FUN(TessOcrUtils, QString(), getLanguages);
|
||||
ACCESS_PRIVATE_FUN(TessOcrUtils, RecognitionResult(Pix*, ResultType), getRecognizeResult);
|
||||
ACCESS_PRIVATE_FUN(TessOcrUtils, void(ErrorCode, const QString,const ResultType,RecognitionResult &), setResult);
|
||||
|
||||
|
||||
|
||||
TEST_F(TessOcrUtilsTest, tessOcrUtils)
|
||||
{
|
||||
EXPECT_NE(nullptr, m_tessOCrUtils);
|
||||
}
|
||||
|
||||
|
||||
TEST_F(TessOcrUtilsTest, getRecogitionResultImagePathAndResultType)
|
||||
{
|
||||
//QString imagePath = "/media/wangcong/workspace/wangcong/workspace/qt_workspace/project/deepin-ocr/assets/testocr.png";
|
||||
QString imagePath = QStandardPaths::writableLocation(QStandardPaths::PicturesLocation) + "/Wallpapers/luca-micheli-ruWkmt3nU58-unsplash.jpg";
|
||||
ResultType resultType = ResultType::RESULT_STRING;
|
||||
RecognitionResult recognitionResult = m_tessOCrUtils->getRecogitionResult(imagePath,resultType);
|
||||
EXPECT_EQ(true, recognitionResult.flag);
|
||||
EXPECT_EQ("", recognitionResult.message);
|
||||
EXPECT_EQ(ErrorCode::OK, recognitionResult.errorCode);
|
||||
EXPECT_EQ(resultType, recognitionResult.resultType);
|
||||
//EXPECT_NE("", recognitionResult.result);
|
||||
}
|
||||
|
||||
TEST_F(TessOcrUtilsTest, getRecogitionResult2ImagePath)
|
||||
{
|
||||
QString imagePath = QStandardPaths::writableLocation(QStandardPaths::PicturesLocation) + "/Wallpapers/luca-micheli-ruWkmt3nU58-unsplash.jpg";
|
||||
RecognitionResult recognitionResult = m_tessOCrUtils->getRecogitionResult(imagePath);
|
||||
recognitionResult = m_tessOCrUtils->getRecogitionResult(imagePath);
|
||||
EXPECT_EQ(true, recognitionResult.flag);
|
||||
EXPECT_EQ("", recognitionResult.message);
|
||||
EXPECT_EQ(ErrorCode::OK, recognitionResult.errorCode);
|
||||
EXPECT_EQ(ResultType::RESULT_STRING, recognitionResult.resultType);
|
||||
//EXPECT_NE("", recognitionResult.result);
|
||||
}
|
||||
|
||||
TEST_F(TessOcrUtilsTest, getRecogitionResultImageAndResultType)
|
||||
{
|
||||
QString imagePath = QStandardPaths::writableLocation(QStandardPaths::PicturesLocation) + "/Wallpapers/luca-micheli-ruWkmt3nU58-unsplash.jpg";
|
||||
ResultType resultType = ResultType::RESULT_STRING;
|
||||
QImage* t_image = new QImage(imagePath);
|
||||
RecognitionResult recognitionResult = TessOcrUtils::instance()->getRecogitionResult(t_image,resultType);
|
||||
EXPECT_EQ(true, recognitionResult.flag);
|
||||
EXPECT_EQ("", recognitionResult.message);
|
||||
EXPECT_EQ(ErrorCode::OK, recognitionResult.errorCode);
|
||||
EXPECT_EQ(resultType, recognitionResult.resultType);
|
||||
//EXPECT_NE("", recognitionResult.result);
|
||||
}
|
||||
|
||||
TEST_F(TessOcrUtilsTest, getRecogitionResultImage)
|
||||
{
|
||||
QString imagePath = QStandardPaths::writableLocation(QStandardPaths::PicturesLocation) + "/Wallpapers/luca-micheli-ruWkmt3nU58-unsplash.jpg";
|
||||
QImage* t_image = new QImage(imagePath);
|
||||
RecognitionResult recognitionResult = TessOcrUtils::instance()->getRecogitionResult(t_image);
|
||||
EXPECT_EQ(true, recognitionResult.flag);
|
||||
EXPECT_EQ("", recognitionResult.message);
|
||||
EXPECT_EQ(ErrorCode::OK, recognitionResult.errorCode);
|
||||
EXPECT_EQ(ResultType::RESULT_STRING, recognitionResult.resultType);
|
||||
//EXPECT_NE("", recognitionResult.result);
|
||||
|
||||
}
|
||||
|
||||
TEST_F(TessOcrUtilsTest, isRunning)
|
||||
{
|
||||
EXPECT_EQ(false, m_tessOCrUtils->isRunning());
|
||||
QString imagePath = QStandardPaths::writableLocation(QStandardPaths::PicturesLocation) + "/Wallpapers/luca-micheli-ruWkmt3nU58-unsplash.jpg";
|
||||
ResultType resultType = ResultType::RESULT_STRING;
|
||||
RecognitionResult recognitionResult = m_tessOCrUtils->getRecogitionResult(imagePath,resultType);
|
||||
EXPECT_EQ(false, m_tessOCrUtils->isRunning());
|
||||
}
|
||||
|
||||
TEST_F(TessOcrUtilsTest, getRecognizeResult)
|
||||
{
|
||||
QString imagePath = QStandardPaths::writableLocation(QStandardPaths::PicturesLocation) + "/Wallpapers/luca-micheli-ruWkmt3nU58-unsplash.jpg";
|
||||
QImage* image = new QImage(imagePath);
|
||||
ResultType resultType = ResultType::RESULT_STRING;
|
||||
Pix *p_image;
|
||||
p_image = pixCreate(image->width(), image->height(), image->depth());
|
||||
p_image->w = static_cast<l_uint32>(image->width());
|
||||
p_image->h = static_cast<l_uint32>(image->height());
|
||||
p_image->d = static_cast<l_uint32>(image->depth());
|
||||
p_image->spp = 3;
|
||||
p_image->wpl = static_cast<l_uint32>(image->width());
|
||||
p_image->refcount = 1;
|
||||
p_image->xres = 0;
|
||||
p_image->yres = 0;
|
||||
p_image->informat = 0;
|
||||
p_image->special = 0;
|
||||
p_image->text = nullptr;
|
||||
p_image->colormap = nullptr;
|
||||
p_image->data = reinterpret_cast<l_uint32*>(image->bits());
|
||||
RecognitionResult recognitionResult = call_private_fun::TessOcrUtilsgetRecognizeResult(*m_tessOCrUtils,p_image,resultType);
|
||||
EXPECT_EQ(true, recognitionResult.flag);
|
||||
EXPECT_EQ("", recognitionResult.message);
|
||||
EXPECT_EQ(ErrorCode::OK, recognitionResult.errorCode);
|
||||
EXPECT_EQ(ResultType::RESULT_STRING, recognitionResult.resultType);
|
||||
}
|
||||
|
||||
TEST_F(TessOcrUtilsTest, setLanguagesPath)
|
||||
{
|
||||
const QString TessDataPath = "/usr/share/deepin-ocr/tesslangs";
|
||||
bool flag = call_private_fun::TessOcrUtilssetLanguagesPath(*m_tessOCrUtils,TessDataPath);
|
||||
//EXPECT_EQ(true, flag);
|
||||
}
|
||||
|
||||
TEST_F(TessOcrUtilsTest, isExistsResultType)
|
||||
{
|
||||
const QString TessDataPath = "/usr/share/deepin-ocr/tesslangs";
|
||||
bool flag = call_private_fun::TessOcrUtilsisExistsResultType(*m_tessOCrUtils,ResultType::RESULT_STRING);
|
||||
//EXPECT_EQ(true, flag);
|
||||
flag = call_private_fun::TessOcrUtilsisExistsResultType(*m_tessOCrUtils,ResultType::RESULT_HTML);
|
||||
//EXPECT_EQ(true, flag);
|
||||
flag = call_private_fun::TessOcrUtilsisExistsResultType(*m_tessOCrUtils,ResultType::UNKNOWN_TYPE);
|
||||
//EXPECT_EQ(false, flag);
|
||||
}
|
||||
|
||||
TEST_F(TessOcrUtilsTest, getLangStr)
|
||||
{
|
||||
QString lang = call_private_fun::TessOcrUtilsgetLangStr(*m_tessOCrUtils,Languages::ENG);
|
||||
EXPECT_EQ("eng", lang);
|
||||
lang = call_private_fun::TessOcrUtilsgetLangStr(*m_tessOCrUtils,Languages::CHI_SIM);
|
||||
EXPECT_EQ("chi_sim", lang);
|
||||
lang = call_private_fun::TessOcrUtilsgetLangStr(*m_tessOCrUtils,Languages::CHI_TRA);
|
||||
EXPECT_EQ("chi_tra", lang);
|
||||
}
|
||||
|
||||
TEST_F(TessOcrUtilsTest, getSystemLang)
|
||||
{
|
||||
Languages lang = call_private_fun::TessOcrUtilsgetSystemLang(*m_tessOCrUtils);
|
||||
EXPECT_NE(Languages::UNKNOWN_LAN, lang);
|
||||
}
|
||||
|
||||
TEST_F(TessOcrUtilsTest, getLanguages)
|
||||
{
|
||||
QString lang = call_private_fun::TessOcrUtilsgetLanguages(*m_tessOCrUtils);
|
||||
EXPECT_NE("", lang);
|
||||
}
|
||||
|
||||
TEST_F(TessOcrUtilsTest, setResult)
|
||||
{
|
||||
RecognitionResult result ;
|
||||
call_private_fun::TessOcrUtilssetResult(*m_tessOCrUtils,ErrorCode::UNKNOWN,"test",ResultType::RESULT_STRING,result);
|
||||
EXPECT_EQ(false, result.flag);
|
||||
EXPECT_EQ(ErrorCode::UNKNOWN, result.errorCode);
|
||||
EXPECT_EQ("test", result.message);
|
||||
EXPECT_EQ(ResultType::RESULT_STRING, result.resultType);
|
||||
EXPECT_EQ("", result.result);
|
||||
}
|
Loading…
Reference in New Issue
Block a user