Home | History | Annotate | Download | only in testing
      1 // Copyright 2015 PDFium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "testing/test_support.h"
      6 
      7 #include <stdio.h>
      8 #include <string.h>
      9 
     10 #include "core/fdrm/crypto/fx_crypt.h"
     11 #include "core/fxcrt/fx_memory.h"
     12 #include "core/fxcrt/fx_string.h"
     13 #include "testing/utils/path_service.h"
     14 
     15 #ifdef PDF_ENABLE_V8
     16 #include "v8/include/libplatform/libplatform.h"
     17 #include "v8/include/v8.h"
     18 #endif
     19 
     20 namespace {
     21 
     22 #ifdef PDF_ENABLE_V8
     23 #ifdef V8_USE_EXTERNAL_STARTUP_DATA
     24 // Returns the full path for an external V8 data file based on either
     25 // the currect exectuable path or an explicit override.
     26 std::string GetFullPathForSnapshotFile(const std::string& exe_path,
     27                                        const std::string& bin_dir,
     28                                        const std::string& filename) {
     29   std::string result;
     30   if (!bin_dir.empty()) {
     31     result = bin_dir;
     32     if (*bin_dir.rbegin() != PATH_SEPARATOR) {
     33       result += PATH_SEPARATOR;
     34     }
     35   } else if (!exe_path.empty()) {
     36     size_t last_separator = exe_path.rfind(PATH_SEPARATOR);
     37     if (last_separator != std::string::npos) {
     38       result = exe_path.substr(0, last_separator + 1);
     39     }
     40   }
     41   result += filename;
     42   return result;
     43 }
     44 
     45 bool GetExternalData(const std::string& exe_path,
     46                      const std::string& bin_dir,
     47                      const std::string& filename,
     48                      v8::StartupData* result_data) {
     49   std::string full_path =
     50       GetFullPathForSnapshotFile(exe_path, bin_dir, filename);
     51   size_t data_length = 0;
     52   std::unique_ptr<char, pdfium::FreeDeleter> data_buffer =
     53       GetFileContents(full_path.c_str(), &data_length);
     54   if (!data_buffer)
     55     return false;
     56 
     57   result_data->data = data_buffer.release();
     58   result_data->raw_size = data_length;
     59   return true;
     60 }
     61 #endif  // V8_USE_EXTERNAL_STARTUP_DATA
     62 
     63 void InitializeV8Common(const char* exe_path, v8::Platform** platform) {
     64   v8::V8::InitializeICUDefaultLocation(exe_path);
     65 
     66   *platform = v8::platform::CreateDefaultPlatform();
     67   v8::V8::InitializePlatform(*platform);
     68 
     69   // By enabling predictable mode, V8 won't post any background tasks.
     70   // By enabling GC, it makes it easier to chase use-after-free.
     71   const char v8_flags[] = "--predictable --expose-gc";
     72   v8::V8::SetFlagsFromString(v8_flags, static_cast<int>(strlen(v8_flags)));
     73   v8::V8::Initialize();
     74 }
     75 #endif  // PDF_ENABLE_V8
     76 
     77 }  // namespace
     78 
     79 std::unique_ptr<char, pdfium::FreeDeleter> GetFileContents(const char* filename,
     80                                                            size_t* retlen) {
     81   FILE* file = fopen(filename, "rb");
     82   if (!file) {
     83     fprintf(stderr, "Failed to open: %s\n", filename);
     84     return nullptr;
     85   }
     86   (void)fseek(file, 0, SEEK_END);
     87   size_t file_length = ftell(file);
     88   if (!file_length) {
     89     return nullptr;
     90   }
     91   (void)fseek(file, 0, SEEK_SET);
     92   std::unique_ptr<char, pdfium::FreeDeleter> buffer(
     93       static_cast<char*>(malloc(file_length)));
     94   if (!buffer) {
     95     return nullptr;
     96   }
     97   size_t bytes_read = fread(buffer.get(), 1, file_length, file);
     98   (void)fclose(file);
     99   if (bytes_read != file_length) {
    100     fprintf(stderr, "Failed to read: %s\n", filename);
    101     return nullptr;
    102   }
    103   *retlen = bytes_read;
    104   return buffer;
    105 }
    106 
    107 std::string GetPlatformString(FPDF_WIDESTRING wstr) {
    108   WideString wide_string =
    109       WideString::FromUTF16LE(wstr, WideString::WStringLength(wstr));
    110   return std::string(wide_string.UTF8Encode().c_str());
    111 }
    112 
    113 std::wstring GetPlatformWString(FPDF_WIDESTRING wstr) {
    114   if (!wstr)
    115     return nullptr;
    116 
    117   size_t characters = 0;
    118   while (wstr[characters])
    119     ++characters;
    120 
    121   std::wstring platform_string(characters, L'\0');
    122   for (size_t i = 0; i < characters + 1; ++i) {
    123     const unsigned char* ptr = reinterpret_cast<const unsigned char*>(&wstr[i]);
    124     platform_string[i] = ptr[0] + 256 * ptr[1];
    125   }
    126   return platform_string;
    127 }
    128 
    129 std::vector<std::string> StringSplit(const std::string& str, char delimiter) {
    130   std::vector<std::string> result;
    131   size_t pos = 0;
    132   while (1) {
    133     size_t found = str.find(delimiter, pos);
    134     if (found == std::string::npos)
    135       break;
    136 
    137     result.push_back(str.substr(pos, found - pos));
    138     pos = found + 1;
    139   }
    140   result.push_back(str.substr(pos));
    141   return result;
    142 }
    143 
    144 std::unique_ptr<unsigned short, pdfium::FreeDeleter> GetFPDFWideString(
    145     const std::wstring& wstr) {
    146   size_t length = sizeof(uint16_t) * (wstr.length() + 1);
    147   std::unique_ptr<unsigned short, pdfium::FreeDeleter> result(
    148       static_cast<unsigned short*>(malloc(length)));
    149   char* ptr = reinterpret_cast<char*>(result.get());
    150   size_t i = 0;
    151   for (wchar_t w : wstr) {
    152     ptr[i++] = w & 0xff;
    153     ptr[i++] = (w >> 8) & 0xff;
    154   }
    155   ptr[i++] = 0;
    156   ptr[i] = 0;
    157   return result;
    158 }
    159 
    160 std::string CryptToBase16(const uint8_t* digest) {
    161   static char const zEncode[] = "0123456789abcdef";
    162   std::string ret;
    163   ret.resize(32);
    164   for (int i = 0, j = 0; i < 16; i++, j += 2) {
    165     uint8_t a = digest[i];
    166     ret[j] = zEncode[(a >> 4) & 0xf];
    167     ret[j + 1] = zEncode[a & 0xf];
    168   }
    169   return ret;
    170 }
    171 
    172 std::string GenerateMD5Base16(const uint8_t* data, uint32_t size) {
    173   uint8_t digest[16];
    174   CRYPT_MD5Generate(data, size, digest);
    175   return CryptToBase16(digest);
    176 }
    177 
    178 #ifdef PDF_ENABLE_V8
    179 #ifdef V8_USE_EXTERNAL_STARTUP_DATA
    180 bool InitializeV8ForPDFium(const std::string& exe_path,
    181                            const std::string& bin_dir,
    182                            v8::StartupData* natives_blob,
    183                            v8::StartupData* snapshot_blob,
    184                            v8::Platform** platform) {
    185   InitializeV8Common(exe_path.c_str(), platform);
    186   if (natives_blob && snapshot_blob) {
    187     if (!GetExternalData(exe_path, bin_dir, "natives_blob.bin", natives_blob))
    188       return false;
    189     if (!GetExternalData(exe_path, bin_dir, "snapshot_blob.bin", snapshot_blob))
    190       return false;
    191     v8::V8::SetNativesDataBlob(natives_blob);
    192     v8::V8::SetSnapshotDataBlob(snapshot_blob);
    193   }
    194   return true;
    195 }
    196 #else   // V8_USE_EXTERNAL_STARTUP_DATA
    197 bool InitializeV8ForPDFium(const std::string& exe_path,
    198                            v8::Platform** platform) {
    199   InitializeV8Common(exe_path.c_str(), platform);
    200   return true;
    201 }
    202 #endif  // V8_USE_EXTERNAL_STARTUP_DATA
    203 #endif  // PDF_ENABLE_V8
    204 
    205 TestLoader::TestLoader(const char* pBuf, size_t len)
    206     : m_pBuf(pBuf), m_Len(len) {
    207 }
    208 
    209 // static
    210 int TestLoader::GetBlock(void* param,
    211                          unsigned long pos,
    212                          unsigned char* pBuf,
    213                          unsigned long size) {
    214   TestLoader* pLoader = static_cast<TestLoader*>(param);
    215   if (pos + size < pos || pos + size > pLoader->m_Len)
    216     return 0;
    217 
    218   memcpy(pBuf, pLoader->m_pBuf + pos, size);
    219   return 1;
    220 }
    221