// Copyright 2015 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. #include "testing/test_support.h" #include <stdio.h> #include <string.h> #include <string> #include "core/fxcrt/fx_memory.h" #include "testing/utils/path_service.h" #ifdef PDF_ENABLE_V8 #include "v8/include/libplatform/libplatform.h" #endif namespace { #ifdef PDF_ENABLE_V8 #ifdef V8_USE_EXTERNAL_STARTUP_DATA // Returns the full path for an external V8 data file based on either // the currect exectuable path or an explicit override. std::string GetFullPathForSnapshotFile(const std::string& exe_path, const std::string& bin_dir, const std::string& filename) { std::string result; if (!bin_dir.empty()) { result = bin_dir; if (*bin_dir.rbegin() != PATH_SEPARATOR) { result += PATH_SEPARATOR; } } else if (!exe_path.empty()) { size_t last_separator = exe_path.rfind(PATH_SEPARATOR); if (last_separator != std::string::npos) { result = exe_path.substr(0, last_separator + 1); } } result += filename; return result; } bool GetExternalData(const std::string& exe_path, const std::string& bin_dir, const std::string& filename, v8::StartupData* result_data) { std::string full_path = GetFullPathForSnapshotFile(exe_path, bin_dir, filename); size_t data_length = 0; std::unique_ptr<char, pdfium::FreeDeleter> data_buffer = GetFileContents(full_path.c_str(), &data_length); if (!data_buffer) return false; result_data->data = data_buffer.release(); result_data->raw_size = data_length; return true; } #endif // V8_USE_EXTERNAL_STARTUP_DATA void InitializeV8Common(const char* exe_path, v8::Platform** platform) { v8::V8::InitializeICUDefaultLocation(exe_path); *platform = v8::platform::CreateDefaultPlatform(); v8::V8::InitializePlatform(*platform); // By enabling predictable mode, V8 won't post any background tasks. // By enabling GC, it makes it easier to chase use-after-free. const char v8_flags[] = "--predictable --expose-gc"; v8::V8::SetFlagsFromString(v8_flags, static_cast<int>(strlen(v8_flags))); v8::V8::Initialize(); } #endif // PDF_ENABLE_V8 } // namespace std::unique_ptr<char, pdfium::FreeDeleter> GetFileContents(const char* filename, size_t* retlen) { FILE* file = fopen(filename, "rb"); if (!file) { fprintf(stderr, "Failed to open: %s\n", filename); return nullptr; } (void)fseek(file, 0, SEEK_END); size_t file_length = ftell(file); if (!file_length) { return nullptr; } (void)fseek(file, 0, SEEK_SET); std::unique_ptr<char, pdfium::FreeDeleter> buffer( static_cast<char*>(malloc(file_length))); if (!buffer) { return nullptr; } size_t bytes_read = fread(buffer.get(), 1, file_length, file); (void)fclose(file); if (bytes_read != file_length) { fprintf(stderr, "Failed to read: %s\n", filename); return nullptr; } *retlen = bytes_read; return buffer; } std::wstring GetPlatformWString(FPDF_WIDESTRING wstr) { if (!wstr) return nullptr; size_t characters = 0; while (wstr[characters]) ++characters; std::wstring platform_string(characters, L'\0'); for (size_t i = 0; i < characters + 1; ++i) { const unsigned char* ptr = reinterpret_cast<const unsigned char*>(&wstr[i]); platform_string[i] = ptr[0] + 256 * ptr[1]; } return platform_string; } std::vector<std::string> StringSplit(const std::string& str, char delimiter) { std::vector<std::string> result; size_t pos = 0; while (1) { size_t found = str.find(delimiter, pos); if (found == std::string::npos) break; result.push_back(str.substr(pos, found - pos)); pos = found + 1; } result.push_back(str.substr(pos)); return result; } std::unique_ptr<unsigned short, pdfium::FreeDeleter> GetFPDFWideString( const std::wstring& wstr) { size_t length = sizeof(uint16_t) * (wstr.length() + 1); std::unique_ptr<unsigned short, pdfium::FreeDeleter> result( static_cast<unsigned short*>(malloc(length))); char* ptr = reinterpret_cast<char*>(result.get()); size_t i = 0; for (wchar_t w : wstr) { ptr[i++] = w & 0xff; ptr[i++] = (w >> 8) & 0xff; } ptr[i++] = 0; ptr[i] = 0; return result; } std::string CryptToBase16(const uint8_t* digest) { static char const zEncode[] = "0123456789abcdef"; std::string ret; ret.resize(32); for (int i = 0, j = 0; i < 16; i++, j += 2) { uint8_t a = digest[i]; ret[j] = zEncode[(a >> 4) & 0xf]; ret[j + 1] = zEncode[a & 0xf]; } return ret; } std::string GenerateMD5Base16(const uint8_t* data, uint32_t size) { uint8_t digest[16]; CRYPT_MD5Generate(data, size, digest); return CryptToBase16(digest); } #ifdef PDF_ENABLE_V8 #ifdef V8_USE_EXTERNAL_STARTUP_DATA bool InitializeV8ForPDFium(const std::string& exe_path, const std::string& bin_dir, v8::StartupData* natives_blob, v8::StartupData* snapshot_blob, v8::Platform** platform) { InitializeV8Common(exe_path.c_str(), platform); if (natives_blob && snapshot_blob) { if (!GetExternalData(exe_path, bin_dir, "natives_blob.bin", natives_blob)) return false; if (!GetExternalData(exe_path, bin_dir, "snapshot_blob.bin", snapshot_blob)) return false; v8::V8::SetNativesDataBlob(natives_blob); v8::V8::SetSnapshotDataBlob(snapshot_blob); } return true; } #else // V8_USE_EXTERNAL_STARTUP_DATA bool InitializeV8ForPDFium(const std::string& exe_path, v8::Platform** platform) { InitializeV8Common(exe_path.c_str(), platform); return true; } #endif // V8_USE_EXTERNAL_STARTUP_DATA #endif // PDF_ENABLE_V8 TestLoader::TestLoader(const char* pBuf, size_t len) : m_pBuf(pBuf), m_Len(len) { } // static int TestLoader::GetBlock(void* param, unsigned long pos, unsigned char* pBuf, unsigned long size) { TestLoader* pLoader = static_cast<TestLoader*>(param); if (pos + size < pos || pos + size > pLoader->m_Len) return 0; memcpy(pBuf, pLoader->m_pBuf + pos, size); return 1; } TestSaver::TestSaver() { FPDF_FILEWRITE::version = 1; FPDF_FILEWRITE::WriteBlock = WriteBlockCallback; } void TestSaver::ClearString() { m_String.clear(); } // static int TestSaver::WriteBlockCallback(FPDF_FILEWRITE* pFileWrite, const void* data, unsigned long size) { TestSaver* pThis = static_cast<TestSaver*>(pFileWrite); pThis->m_String.append(static_cast<const char*>(data), size); return 1; } // static int TestSaver::GetBlockFromString(void* param, unsigned long pos, unsigned char* buf, unsigned long size) { std::string* new_file = static_cast<std::string*>(param); if (!new_file || pos + size < pos) return 0; unsigned long file_size = new_file->size(); if (pos + size > file_size) return 0; memcpy(buf, new_file->data() + pos, size); return 1; }