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
20namespace {
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.
26std::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
45bool 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
63void 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
79std::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
107std::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
113std::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
129std::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
144std::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
160std::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
172std::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
180bool 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
197bool 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
205TestLoader::TestLoader(const char* pBuf, size_t len)
206    : m_pBuf(pBuf), m_Len(len) {
207}
208
209// static
210int 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