NS_IMETHODIMP nsBidiKeyboard::SetLangFromBidiLevel(uint8_t aLevel)
{
  nsresult result = SetupBidiKeyboards();
  if (NS_FAILED(result))
    return result;

  // call LoadKeyboardLayout() only if the target keyboard layout is different from the current
  wchar_t currentLocaleName[KL_NAMELENGTH];
  wcsncpy(currentLocaleName, char16ptr_t((aLevel & 1) ? mRTLKeyboard : mLTRKeyboard), KL_NAMELENGTH);
  currentLocaleName[KL_NAMELENGTH-1] = '\0'; // null terminate

  NS_ASSERTION(*currentLocaleName, 
    "currentLocaleName has string length == 0");

#if 0
  /* This implementation of automatic keyboard layout switching is too buggy to be useful
     and the feature itself is inconsistent with Windows. See Bug 162242 */
  if (strcmp(mCurrentLocaleName, currentLocaleName)) {
    if (!::LoadKeyboardLayout(currentLocaleName, KLF_ACTIVATE | KLF_SUBSTITUTE_OK)) {
      return NS_ERROR_FAILURE;
    }
  }
#endif

  return NS_OK;
}
NS_IMETHODIMP nsPrintSettingsWin::SetDriverName(const char16_t * aDriverName)
{
  if (mDriverName) {
    free(mDriverName);
  }
  mDriverName = aDriverName?wcsdup(char16ptr_t(aDriverName)):nullptr;
  return NS_OK;
}
/* [noscript] attribute charPtr deviceName; */
NS_IMETHODIMP nsPrintSettingsWin::SetDeviceName(const char16_t * aDeviceName)
{
  if (mDeviceName) {
    nsMemory::Free(mDeviceName);
  }
  mDeviceName = aDeviceName?wcsdup(char16ptr_t(aDeviceName)):nullptr;
  return NS_OK;
}
/* [noscript] attribute charPtr driverName; */
NS_IMETHODIMP nsPrintSettingsWin::SetDriverName(const PRUnichar * aDriverName)
{
  if (mDriverName) {
    nsMemory::Free(mDriverName);
  }
  mDriverName = aDriverName?wcsdup(char16ptr_t(aDriverName)):nullptr;
  return NS_OK;
}
int32_t
CompareVersions(const char16_t* aStrA, const char16_t* aStrB)
{
  wchar_t* A2 = wcsdup(char16ptr_t(aStrA));
  if (!A2) {
    return 1;
  }

  wchar_t* B2 = wcsdup(char16ptr_t(aStrB));
  if (!B2) {
    free(A2);
    return 1;
  }

  int32_t result;
  wchar_t* a = A2;
  wchar_t* b = B2;

  do {
    VersionPartW va, vb;

    a = ParseVP(a, va);
    b = ParseVP(b, vb);

    result = CompareVP(va, vb);
    if (result) {
      break;
    }

  } while (a || b);

  free(A2);
  free(B2);

  return result;
}
NS_IMETHODIMP
nsLocalFile::GetRelativeDescriptor(nsIFile* aFromFile, nsACString& aResult)
{
  if (NS_WARN_IF(!aFromFile)) {
    return NS_ERROR_INVALID_ARG;
  }
  const int32_t kMaxNodesInPath = 32;

  //
  // aResult will be UTF-8 encoded
  //

  nsresult rv;
  aResult.Truncate(0);

  nsAutoString thisPath, fromPath;
  char16_t* thisNodes[kMaxNodesInPath];
  char16_t* fromNodes[kMaxNodesInPath];
  int32_t thisNodeCnt, fromNodeCnt, nodeIndex;

  rv = GetPath(thisPath);
  if (NS_FAILED(rv)) {
    return rv;
  }
  rv = aFromFile->GetPath(fromPath);
  if (NS_FAILED(rv)) {
    return rv;
  }

  // get raw pointer to mutable string buffer
  char16_t* thisPathPtr;
  thisPath.BeginWriting(thisPathPtr);
  char16_t* fromPathPtr;
  fromPath.BeginWriting(fromPathPtr);

  thisNodeCnt = SplitPath(thisPathPtr, thisNodes, kMaxNodesInPath);
  fromNodeCnt = SplitPath(fromPathPtr, fromNodes, kMaxNodesInPath);
  if (thisNodeCnt < 0 || fromNodeCnt < 0) {
    return NS_ERROR_FAILURE;
  }

  for (nodeIndex = 0; nodeIndex < thisNodeCnt && nodeIndex < fromNodeCnt; ++nodeIndex) {
#ifdef XP_WIN
    if (_wcsicmp(char16ptr_t(thisNodes[nodeIndex]), char16ptr_t(fromNodes[nodeIndex]))) {
      break;
    }
#else
    if (nsCRT::strcmp(thisNodes[nodeIndex], fromNodes[nodeIndex])) {
      break;
    }
#endif
  }

  int32_t branchIndex = nodeIndex;
  for (nodeIndex = branchIndex; nodeIndex < fromNodeCnt; ++nodeIndex) {
    aResult.AppendLiteral("../");
  }
  for (nodeIndex = branchIndex; nodeIndex < thisNodeCnt; nodeIndex++) {
    NS_ConvertUTF16toUTF8 nodeStr(thisNodes[nodeIndex]);
    aResult.Append(nodeStr);
    if (nodeIndex + 1 < thisNodeCnt) {
      aResult.Append('/');
    }
  }

  return NS_OK;
}