HRESULT Helpers::LoadScriptFromFile(LPCSTR filenameToLoad, LPCSTR& contents, UINT* lengthBytesOut /*= nullptr*/, std::string* fullPath /*= nullptr*/, bool shouldMute /*=false */) { static char sHostApplicationPathBuffer[MAX_URI_LENGTH]; static uint sHostApplicationPathBufferLength = (uint) -1; char combinedPathBuffer[MAX_URI_LENGTH]; HRESULT hr = S_OK; BYTE * pRawBytes = nullptr; BYTE * pRawBytesFromMap = nullptr; UINT lengthBytes = 0; contents = nullptr; FILE * file = NULL; size_t bufferLength = 0; LPCSTR filename = fullPath == nullptr ? filenameToLoad : LPCSTR(fullPath->c_str()); if (sHostApplicationPathBufferLength == (uint)-1) { // consider incoming filename as the host app and base its' path for others sHostApplicationPathBufferLength = GetPathNameLocation(filename); if (sHostApplicationPathBufferLength == -1) { // host app has no path info. (it must be located on current folder!) sHostApplicationPathBufferLength = 0; } else { sHostApplicationPathBufferLength += 1; Assert(sHostApplicationPathBufferLength < MAX_URI_LENGTH); // save host app's path and fix the path separator for platform pathcpy(sHostApplicationPathBuffer, filename, sHostApplicationPathBufferLength); } sHostApplicationPathBuffer[sHostApplicationPathBufferLength] = char(0); } else if (filename[0] != '/' && filename[0] != '\\' && fullPath == nullptr) // make sure it's not a full path { // concat host path and filename uint len = ConcatPath(sHostApplicationPathBuffer, sHostApplicationPathBufferLength, filename, combinedPathBuffer, MAX_URI_LENGTH); if (len == (uint)-1) { hr = E_FAIL; goto Error; } filename = combinedPathBuffer; } // check if have it registered AutoString *data; if (SourceMap::Find(filenameToLoad, strlen(filenameToLoad), &data) || SourceMap::Find(filename, strlen(filename), &data)) { pRawBytesFromMap = (BYTE*) data->GetString(); lengthBytes = (UINT) data->GetLength(); } else { // Open the file as a binary file to prevent CRT from handling encoding, line-break conversions, // etc. if (fopen_s(&file, filename, "rb") != 0) { if (!HostConfigFlags::flags.MuteHostErrorMsgIsEnabled && !shouldMute) { #ifdef _WIN32 DWORD lastError = GetLastError(); char16 wszBuff[MAX_URI_LENGTH]; fprintf(stderr, "Error in opening file '%s' ", filename); wszBuff[0] = 0; if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, lastError, 0, wszBuff, _countof(wszBuff), nullptr)) { fwprintf(stderr, _u(": %s"), wszBuff); } fwprintf(stderr, _u("\n")); #elif defined(_POSIX_VERSION) fprintf(stderr, "Error in opening file: "); perror(filename); #endif } IfFailGo(E_FAIL); } } if (file != NULL) { // Determine the file length, in bytes. fseek(file, 0, SEEK_END); lengthBytes = ftell(file); fseek(file, 0, SEEK_SET); } if (lengthBytes != 0) { bufferLength = lengthBytes + sizeof(BYTE); pRawBytes = (LPBYTE)malloc(bufferLength); } else { bufferLength = 1; pRawBytes = (LPBYTE)malloc(bufferLength); } if (nullptr == pRawBytes) { fwprintf(stderr, _u("out of memory")); IfFailGo(E_OUTOFMEMORY); } if (lengthBytes != 0) { if (file != NULL) { // // Read the entire content as a binary block. // size_t readBytes = fread(pRawBytes, sizeof(BYTE), lengthBytes, file); if (readBytes < lengthBytes * sizeof(BYTE)) { IfFailGo(E_FAIL); } } else // from module source register { // Q: module source is on persistent memory. Why do we use the copy instead? // A: if we use the same memory twice, ch doesn't know that during FinalizeCallback free. // the copy memory will be freed by the finalizer Assert(pRawBytesFromMap); memcpy_s(pRawBytes, bufferLength, pRawBytesFromMap, lengthBytes); } } if (pRawBytes) { pRawBytes[lengthBytes] = 0; // Null terminate it. Could be UTF16 } if (file != NULL) { // // Read encoding to make sure it's supported // // Warning: The UNICODE buffer for parsing is supposed to be provided by the host. // This is not a complete read of the encoding. Some encodings like UTF7, UTF1, EBCDIC, SCSU, BOCU could be // wrongly classified as ANSI // #pragma warning(push) // suppressing prefast warning that "readable size is bufferLength // bytes but 2 may be read" as bufferLength is clearly > 2 in the code that follows #pragma warning(disable:6385) C_ASSERT(sizeof(WCHAR) == 2); if (bufferLength > 2) { __analysis_assume(bufferLength > 2); #pragma prefast(push) #pragma prefast(disable:6385, "PREfast incorrectly reports this as an out-of-bound access."); if ((pRawBytes[0] == 0xFE && pRawBytes[1] == 0xFF) || (pRawBytes[0] == 0xFF && pRawBytes[1] == 0xFE) || (bufferLength > 4 && pRawBytes[0] == 0x00 && pRawBytes[1] == 0x00 && ((pRawBytes[2] == 0xFE && pRawBytes[3] == 0xFF) || (pRawBytes[2] == 0xFF && pRawBytes[3] == 0xFE)))) { // unicode unsupported fwprintf(stderr, _u("unsupported file encoding. Only ANSI and UTF8 supported")); IfFailGo(E_UNEXPECTED); } #pragma prefast(pop) } #pragma warning(pop) } contents = reinterpret_cast<LPCSTR>(pRawBytes); Error: if (SUCCEEDED(hr)) { if (lengthBytesOut) { *lengthBytesOut = lengthBytes; } } if (file != NULL) { fclose(file); } if (pRawBytes && reinterpret_cast<LPCSTR>(pRawBytes) != contents) { free(pRawBytes); } return hr; }
bool Debugger::CompareOrWriteBaselineFile(LPCSTR fileName) { AutoRestoreContext autoRestoreContext(this->m_context); // Pass in undefined for 'this' JsValueRef undefinedRef; IfJsrtErrorFailLogAndRetFalse(ChakraRTInterface::JsGetUndefinedValue(&undefinedRef)); JsValueRef result = JS_INVALID_REFERENCE; bool testPassed = false; if (HostConfigFlags::flags.dbgbaselineIsEnabled) { this->CallFunction("Verify", &result); JsValueRef numberVal; IfJsrtErrorFailLogAndRetFalse(ChakraRTInterface::JsConvertValueToNumber(result, &numberVal)); int val; IfJsrtErrorFailLogAndRetFalse(ChakraRTInterface::JsNumberToInt(numberVal, &val)); testPassed = (val == 0); } if (!testPassed) { this->CallFunction("GetOutputJson", &result); AutoString baselineData; IfJsrtErrorFailLogAndRetFalse(baselineData.Initialize(result)); char16 baselineFilename[256]; swprintf_s(baselineFilename, HostConfigFlags::flags.dbgbaselineIsEnabled ? _u("%S.dbg.baseline.rebase") : _u("%S.dbg.baseline"), fileName); FILE *file = nullptr; if (_wfopen_s(&file, baselineFilename, _u("wt")) != 0) { return false; } if (file != nullptr) { int countWritten = static_cast<int>(fwrite(baselineData.GetString(), sizeof(char), baselineData.GetLength(), file)); Assert(baselineData.GetLength() <= INT_MAX); if (countWritten != (int)baselineData.GetLength()) { Assert(false); return false; } fclose(file); } if (!HostConfigFlags::flags.dbgbaselineIsEnabled) { wprintf(_u("No baseline file specified, baseline created at '%s'\n"), baselineFilename); } else { Helpers::LogError(_u("Rebase file created at '%s'\n"), baselineFilename); } } return true; }