text: /*++
  
  Copyright (c) 2000 Microsoft Corporation
  
  Module Name:
  
      cliutils.cpp
  
  Abstract:
  
      Implements internal CLI unit utilities
  
  Author:
  
      Ran Kalach          [rankala]         8-March-2000
  
  Revision History:
  
  --*/
  
  #include "stdafx.h"
  #include "HsmConn.h"
  
  static GUID g_nullGuid = GUID_NULL;
  
  HRESULT
  ValidateLimitsArg(
     IN DWORD dwArgValue,
     IN DWORD dwArgId,
     IN DWORD dwMinLimit,
     IN DWORD dwMaxLimit
  )
  /*++
  
  Routine Description:
  
      Validates the argument and print error message if necessary
  
  Arguments:
  
      dwArgValue      - The value to check
      dwArgId         - Id for resource string of the arg
      dwMinLimit      - The Min limit to compare, INVALID_DWORD_ARG for Max compare
      dwMaxLimit      - The Max limit to compare, INVALID_DWORD_ARG for Min compare
  
  Return Value:
  
      S_OK            - The argument is OK (or not in use)
      E_INVALIDARG    - The argument is not in the limit range
  
  --*/
  {
      HRESULT                     hr = S_OK;
  
      WsbTraceIn(OLESTR("ValidateOneLimitArg"), OLESTR(""));
  
      try {
          CWsbStringPtr   param;
          WCHAR           strLongParm1[30];
          WCHAR           strLongParm2[30];
          WCHAR           strLongParm3[30];
  
          if (INVALID_DWORD_ARG != dwArgValue) {
              if ((INVALID_DWORD_ARG != dwMinLimit) && (INVALID_DWORD_ARG != dwMaxLimit)) {
                  // Min-Max test
                  if ((dwArgValue < dwMinLimit) || (dwArgValue > dwMaxLimit)) {
                      WsbAffirmHr(param.LoadFromRsc(g_hInstance, dwArgId));
                      swprintf(strLongParm1, OLESTR("%lu"), dwArgValue);
                      swprintf(strLongParm2, OLESTR("%lu"), dwMinLimit);
                      swprintf(strLongParm3, OLESTR("%lu"), dwMaxLimit);
                      WsbTraceAndPrint(CLI_MESSAGE_INVALID_ARG3, (WCHAR *)param, 
                              strLongParm1, strLongParm2, strLongParm3, NULL);
                      WsbThrow(E_INVALIDARG);
                  }
              } else if (INVALID_DWORD_ARG != dwMinLimit) {
                  // Min test
                  if (dwArgValue < dwMinLimit) {
                      WsbAffirmHr(param.LoadFromRsc(g_hInstance, dwArgId));
                      swprintf(strLongParm1, OLESTR("%lu"), dwArgValue);
                      swprintf(strLongParm2, OLESTR("%lu"), dwMinLimit);
                      WsbTraceAndPrint(CLI_MESSAGE_INVALID_ARG1, (WCHAR *)param, 
                              strLongParm1, strLongParm2, NULL);
                      WsbThrow(E_INVALIDARG);
                  }
              } else if (INVALID_DWORD_ARG != dwMaxLimit) {
                  // Max test
                  if (dwArgValue > dwMaxLimit) {
                      WsbAffirmHr(param.LoadFromRsc(g_hInstance, dwArgId));
                      swprintf(strLongParm1, OLESTR("%lu"), dwArgValue);
                      swprintf(strLongParm2, OLESTR("%lu"), dwMaxLimit);
                      WsbTraceAndPrint(CLI_MESSAGE_INVALID_ARG2, (WCHAR *)param, 
                              strLongParm1, strLongParm2, NULL);
                      WsbThrow(E_INVALIDARG);
                  }
               }
          }
  
      } WsbCatch(hr);
  
      WsbTraceOut(OLESTR("ValidateOneLimitArg"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  
      return (hr);
  }
  
  HRESULT SaveServersPersistData(
      void
  )
  /*++
  
  Routine Description:
  
      Save persistent data for HSM servers
  
  Arguments:
  
      None
  
  Return Value:
  
      S_OK            - The persistent data is saved successfully for all HSM servers
  
  --*/
  {
      HRESULT                     hr = S_OK;
  
      WsbTraceIn(OLESTR("SaveServersPersistData"), OLESTR(""));
  
      try {
          CComPtr<IHsmServer>             pHsm;
          CComPtr<IFsaServer>             pFsa;
          CComPtr<IWsbServer>             pWsbServer;
  
          // Engine
          WsbAffirmHr(HsmConnectFromId(HSMCONN_TYPE_HSM, g_nullGuid, IID_IHsmServer, (void**)&pHsm));
          WsbAffirmHr(pHsm->SavePersistData());
  
          // Fsa
          WsbAffirmHr(HsmConnectFromId(HSMCONN_TYPE_FSA, g_nullGuid, IID_IFsaServer, (void**)&pFsa));
          WsbAffirmHr(pFsa->QueryInterface(IID_IWsbServer, (void**)&pWsbServer));
          WsbAffirmHr(pWsbServer->SaveAll());
  
      } WsbCatch(hr);
  
      WsbTraceOut(OLESTR("SaveServersPersistData"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  
      return (hr);
  }
  
  /* converts numbers into sort formats
   *      532     -> 523 bytes
   *      1340    -> 1.3KB
   *      23506   -> 23.5KB
   *              -> 2.4MB
   *              -> 5.2GB
   */
  
  // NOTE: This code is cloned from MS source /shell/shelldll/util.c (and from \hsm\gui\inc\rsutil.cpp)
  
  #define HIDWORD(_qw)    (DWORD)((_qw)>>32)
  #define LODWORD(_qw)    (DWORD)(_qw)
  #define ARRAYSIZE(a)    (sizeof(a)/sizeof(a[0]))
  
  const int pwOrders[] = {IDS_BYTES, IDS_ORDERKB, IDS_ORDERMB,
                            IDS_ORDERGB, IDS_ORDERTB, IDS_ORDERPB, IDS_ORDEREB};
  
  HRESULT ShortSizeFormat64(__int64 dw64, LPTSTR szBuf)
  {
      int i;
      UINT wInt, wLen, wDec;
      TCHAR szTemp[10], szOrder[20], szFormat[5];
  
      if (dw64 < 1000) {
          wsprintf(szTemp, TEXT("%d"), LODWORD(dw64));
          i = 0;
          goto AddOrder;
      }
  
      for (i = 1; i<ARRAYSIZE(pwOrders)-1 && dw64 >= 1000L * 1024L; dw64 >>= 10, i++);
          /* do nothing */
  
      wInt = LODWORD(dw64 >> 10);
      AddCommas(wInt, szTemp, 10);
      wLen = lstrlen(szTemp);
      if (wLen < 3)
      {
          wDec = LODWORD(dw64 - (__int64)wInt * 1024L) * 1000 / 1024;
          // At this point, wDec should be between 0 and 1000
          // we want get the top one (or two) digits.
          wDec /= 10;
          if (wLen == 2)
              wDec /= 10;
  
          // Note that we need to set the format before getting the
          // intl char.
          lstrcpy(szFormat, TEXT("%02d"));
  
          szFormat[2] = (TCHAR)( TEXT('0') + 3 - wLen );
          GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL,
                  szTemp+wLen, ARRAYSIZE(szTemp)-wLen);
          wLen = lstrlen(szTemp);
          wLen += wsprintf(szTemp+wLen, szFormat, wDec);
      }
  
  AddOrder:
      LoadString(g_hInstance, pwOrders[i], szOrder, ARRAYSIZE(szOrder));
      wsprintf(szBuf, szOrder, (LPTSTR)szTemp);
  
      return S_OK;
  }
  
  /*
   * takes a DWORD add commas etc to it and puts the result in the buffer
   */
  
  // NOTE: This code is cloned from MS source /shell/shelldll/util.c (and from \hsm\gui\inc\rsutil.cpp)
  
  LPTSTR AddCommas(DWORD dw, LPTSTR pszResult, int nResLen)
  {
      TCHAR  szTemp[20];  // more than enough for a DWORD
      TCHAR  szSep[5];
      NUMBERFMT nfmt;
  
      nfmt.NumDigits=0;
      nfmt.LeadingZero=0;
      GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SGROUPING, szSep, ARRAYSIZE(szSep));
      nfmt.Grouping = _tcstol(szSep, NULL, 10);
      GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, szSep, ARRAYSIZE(szSep));
      nfmt.lpDecimalSep = nfmt.lpThousandSep = szSep;
      nfmt.NegativeOrder= 0;
  
      wsprintf(szTemp, TEXT("%lu"), dw);
  
      if (GetNumberFormat(LOCALE_USER_DEFAULT, 0, szTemp, &nfmt, pszResult, nResLen) == 0)
          lstrcpy(pszResult, szTemp);
  
      return pszResult;
  }
  
  HRESULT 
  FormatFileTime(
      IN FILETIME ft, 
      OUT WCHAR **ppTimeString
  )
  /*++
  
  Routine Description:
  
      Fotmat a time given in GMT (system) time to a string
  
  Arguments:
  
      ft              - The input time in FILETIME format
      ppTimeString    - Output buffer. Caller is expected to free using WsbFree in case of success
  
  Return Value:
  
      S_OK            - If the time is formatted successfully
  
  --*/
  {
      HRESULT                     hr = S_OK;
      WCHAR*                      pTime = NULL;
  
      WsbTraceIn(OLESTR("FormatFileTime"), OLESTR(""));
  
      try {
          FILETIME        ftLocal;
          SYSTEMTIME      stLocal;
  
          WsbAffirm(0 != ppTimeString, E_INVALIDARG);
          *ppTimeString = NULL;
  
          // Translate to local time in SYSTEMTIME format
          WsbAffirmStatus(FileTimeToLocalFileTime(&ft, &ftLocal));
          WsbAffirmStatus(FileTimeToSystemTime(&ftLocal, &stLocal));
  
          // Find required buffer
          int nChars1 = GetDateFormat(LOCALE_SYSTEM_DEFAULT, 0, &stLocal, NULL, NULL, 0);
          int nChars2 = GetTimeFormat(LOCALE_SYSTEM_DEFAULT, 0, &stLocal, NULL, NULL, 0);
          pTime = (WCHAR *)WsbAlloc((nChars1+nChars2+1) * sizeof(WCHAR));
          WsbAffirm(0 != pTime, E_OUTOFMEMORY);
  
          // Create time string
          WsbAffirmStatus(GetDateFormat(LOCALE_SYSTEM_DEFAULT, 0, &stLocal, NULL, pTime, nChars1));
          pTime[nChars1-1] = L' ';
          WsbAffirmStatus(GetTimeFormat(LOCALE_SYSTEM_DEFAULT, 0, &stLocal, NULL, &(pTime[nChars1]), nChars2));
  
          *ppTimeString = pTime;
          
      } WsbCatchAndDo(hr,
          // Free in case of an error
          if (pTime) {
              WsbFree(pTime);
              pTime = NULL;
          }
      );
  
      WsbTraceOut(OLESTR("FormatFileTime"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  
      return (hr);
  }
  
  HRESULT 
  CliGetVolumeDisplayName(
      IN IUnknown *pResourceUnknown, 
      OUT WCHAR **ppDisplayName
  )
  /*++
  
  Routine Description:
  
      Produce a display name for a volume
  
  Arguments:
  
      pResourceUnknown    - The input Fsa Resource object
      ppDisplayName       - Output buffer. Caller is expected to free using WsbFree in case of success
  
  Return Value:
  
      S_OK            - If the name is retrieved successfully
  
  --*/
  {
      HRESULT                     hr = S_OK;
  
      WsbTraceIn(OLESTR("CliGetVolumeDisplayName"), OLESTR(""));
  
      try {
          CComPtr<IFsaResource>   pResource;
  
          // Check and initialize parameters
          WsbAffirm(0 != ppDisplayName, E_INVALIDARG);
          *ppDisplayName = NULL;
          WsbAffirmHr(pResourceUnknown->QueryInterface(IID_IFsaResource, (void **)&pResource));
  
          // Prefer user friendly name
          //  If not exists, use label
          //  If no label, use constant
          CWsbStringPtr userName;
          WsbAffirmHr(pResource->GetUserFriendlyName(&userName, 0));
  
          if (userName.IsEqual(L"")) {
              userName.Free();
              WsbAffirmHr(pResource->GetName(&userName, 0));
              if (userName.IsEqual(L"")) {
                  userName.Free();
                  WsbAffirmHr(userName.LoadFromRsc(g_hInstance, IDS_UNLABELED_VOLUME));
              }
          } 
  
          *ppDisplayName = (WCHAR *)WsbAlloc((wcslen(userName) + 1) * sizeof(WCHAR));
          WsbAffirm(0 != *ppDisplayName, E_OUTOFMEMORY);
          wcscpy(*ppDisplayName, userName);
          
      } WsbCatch(hr);
  
      WsbTraceOut(OLESTR("CliGetVolumeDisplayName"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  
      return (hr);
  }
  