/**
 * Copyright(c) 2011 Trusted Logic.   All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *  * Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *  * Neither the name Trusted Logic nor the names of its
 *    contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifdef __ANDROID32__
#include <stddef.h>
#endif

#include <stdlib.h>
#include <string.h>

#define SST_EXPORTS
#define EXCLUDE_SERVICE_SYSTEM_SST_BASIC_TYPES
#include "sst.h"

/* Included for the TEE management */
#include "pkcs11_internal.h"


static TEEC_Session g_SSTSession;
static bool g_bSSTInitialized = false;


/* ------------------------------------------------------------------------
            TEEC -> SST error code translation
  ------------------------------------------------------------------------- */
static SST_ERROR static_SSTConvertErrorCode(TEEC_Result nError)
{
   switch (nError)
   {
      case TEEC_SUCCESS:
         return SST_SUCCESS;
      case SST_ERROR_BAD_PARAMETERS:
      case SST_ERROR_ACCESS_DENIED:
      case SST_ERROR_ACCESS_CONFLICT:
      case SST_ERROR_CORRUPTED:
      case SST_ERROR_NO_SPACE:
      case SST_ERROR_ITEM_NOT_FOUND:
      case SST_ERROR_OUT_OF_MEMORY:
      case SST_ERROR_OVERFLOW:
         return nError;
      default:
         return SST_ERROR_GENERIC;
   }
}

static TEEC_Session* static_SSTGetSession(void)
{
   if (g_bSSTInitialized)
   {
      return &g_SSTSession;
   }

   return NULL;
}

SST_ERROR SST_EXPORT_API SSTInit(void)
{
   TEEC_Result          nTeeError = TEEC_SUCCESS;
   TEEC_Operation       sOperation;
   uint8_t              nParamType3 = TEEC_NONE;
   void*                pSignatureFile = NULL;
   uint32_t             nSignatureFileLen = 0;
   uint32_t             nLoginType;

   stubMutexLock();
   if (g_bSSTInitialized)
   {
      /* SST library already initialized */
      nTeeError = TEEC_SUCCESS;
      goto end;
   }

   nTeeError = stubInitializeContext();
   if (nTeeError != TEEC_SUCCESS)
   {
      goto end;
   }

   /* Check if there is a signature file.
    * If yes, send it in param3, otherwise use LOGIN_APPLICATION
    */
   nTeeError =  TEEC_ReadSignatureFile(&pSignatureFile, &nSignatureFileLen);
   if (nTeeError == TEEC_ERROR_ITEM_NOT_FOUND)
   {
      nLoginType = TEEC_LOGIN_USER_APPLICATION;
   }
   else
   {
       if (nTeeError != TEEC_SUCCESS)
       {
           goto end;
       }
       sOperation.params[3].tmpref.buffer = pSignatureFile;
       sOperation.params[3].tmpref.size   = nSignatureFileLen;
       nParamType3 = TEEC_MEMREF_TEMP_INPUT;
       nLoginType = TEEC_LOGIN_AUTHENTICATION;
   }

   sOperation.paramTypes = TEEC_PARAM_TYPES(TEEC_NONE, TEEC_NONE, TEEC_NONE, nParamType3);
   nTeeError = TEEC_OpenSession(&g_sContext,
                             &g_SSTSession,              /* OUT session */
                             &SERVICE_UUID,              /* destination UUID */
                             nLoginType,                 /* connectionMethod */
                             NULL,                       /* connectionData */
                             &sOperation,                /* IN OUT operation */
                             NULL                        /* OUT returnOrigin, optional */
                             );
   if (nTeeError != TEEC_SUCCESS)
   {
      goto end_finalize_context;
   }

   g_bSSTInitialized = true;
   stubMutexUnlock();
   return SST_SUCCESS;

end_finalize_context:
   stubFinalizeContext();
end:
   stubMutexUnlock();
   return static_SSTConvertErrorCode(nTeeError);
}

SST_ERROR SST_EXPORT_API SSTTerminate(void)
{
   stubMutexLock();
   if (g_bSSTInitialized)
   {
      TEEC_CloseSession(&g_SSTSession);
      stubFinalizeContext();
      g_bSSTInitialized = false;
   }
   /* else if not intialized => success too */
   stubMutexUnlock();
   return SST_SUCCESS;
}


/* ------------------------------------------------------------------------
                           Other API Functions
------------------------------------------------------------------------- */


/* Check that the input filename is well-formed */
static SST_ERROR static_SSTCheckFileName(const char* pName)
{
   uint32_t i;
   char     c;

   if (pName == NULL)
   {
      return SST_ERROR_BAD_PARAMETERS;
   }

   for (i = 0; i <= SST_MAX_FILENAME; i++)
   {
      c = pName[i];
      if (c == 0)
      {
         /* End of the string */
         return SST_SUCCESS;
      }

      if (c == '/' || c == '\\')
      {
         /* Invalid character */
         return SST_ERROR_BAD_PARAMETERS;
      }

      if (c < 0x20 || c >= 0x7F)
      {
         /* Filename contains illegal characters */
         return SST_ERROR_BAD_PARAMETERS;
      }
   }
   /* Filename is too long. Zero terminator not found */
   return SST_ERROR_BAD_PARAMETERS;
}

static SST_ERROR static_SSTCheckPattern(
      const char* pFilenamePattern)
{
   uint32_t i;
   if(pFilenamePattern == NULL)
   {
      return S_SUCCESS;
   }

   /**
    * Check Forbidden characters.
    */
   for (i = 0; pFilenamePattern[i] != 0; i++)
   {
      if(pFilenamePattern[i] < 0x20 )
      {
         return S_ERROR_BAD_PARAMETERS;
      }
      else if(pFilenamePattern[i] == 0x2F ) /* '/' */
      {
         return S_ERROR_BAD_PARAMETERS;
      }
      else if(pFilenamePattern[i] == 0x5C ) /* '\' */
      {
         /**
          * Must be directly followed by asterisk character or question-mark
          * character.
          */
         if (! ((pFilenamePattern[i+1] == '*' ||
                   pFilenamePattern[i+1] == '?')))
         {
            return S_ERROR_BAD_PARAMETERS;
         }
      }
      else if(pFilenamePattern[i] >= 0x7F )
      {
         return S_ERROR_BAD_PARAMETERS;
      }
   }

   return S_SUCCESS;
}



SST_ERROR SST_EXPORT_API SSTOpen(const char* pFilename,
                                 uint32_t    nFlags,
                                 uint32_t    nReserved,
                                 SST_HANDLE* phFile)
{
   TEEC_Session*     pSession;
   TEEC_Result       nError;
   TEEC_Operation    sOperation;
   uint32_t          nReturnOrigin;
   SST_ERROR         nErrorCode = SST_SUCCESS;

   if (phFile == NULL || nReserved != 0)
   {
      return SST_ERROR_BAD_PARAMETERS;
   }

   *phFile = SST_HANDLE_INVALID;

   nErrorCode = static_SSTCheckFileName(pFilename);
   if (nErrorCode != SST_SUCCESS)
   {
      return nErrorCode;
   }

   pSession = static_SSTGetSession();
   if (pSession == NULL)
   {
      return SST_ERROR_GENERIC;
   }

   sOperation.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_MEMREF_TEMP_INPUT, TEEC_NONE, TEEC_NONE);
   sOperation.params[0].value.a = 1;      /* Private storage */
   sOperation.params[0].value.b = nFlags; /* Access flags */
   sOperation.params[1].tmpref.buffer = (void*)pFilename;
   sOperation.params[1].tmpref.size   = strlen(pFilename);
   nError = TEEC_InvokeCommand(pSession,
                               SERVICE_SYSTEM_SST_OPEN_COMMAND_ID,   /* commandID */
                               &sOperation,                 /* IN OUT operation */
                               &nReturnOrigin               /* OUT returnOrigin, optional */
                              );
   if (nError == TEEC_SUCCESS)
   {
      *phFile = (SST_HANDLE)sOperation.params[0].value.a;
   }

   return static_SSTConvertErrorCode(nError);
}

SST_ERROR SST_EXPORT_API SSTCloseHandle(SST_HANDLE  hFile)
{
   TEEC_Session*     pSession;
   TEEC_Result        nError;
   TEEC_Operation    sOperation;
   uint32_t          nReturnOrigin;

   if (hFile == S_HANDLE_NULL)
   {
      return SST_SUCCESS;
   }

   pSession = static_SSTGetSession();
   if (pSession == NULL)
   {
      return SST_ERROR_GENERIC;
   }

   sOperation.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT, TEEC_NONE, TEEC_NONE, TEEC_NONE);
   sOperation.params[0].value.a = hFile;
   nError = TEEC_InvokeCommand(pSession,
                               SERVICE_SYSTEM_SST_CLOSE_COMMAND_ID, /* commandID */
                               &sOperation,                  /* IN OUT operation */
                               &nReturnOrigin            /* OUT returnOrigin, optional */
                              );

   return static_SSTConvertErrorCode(nError);
}

SST_ERROR SST_EXPORT_API SSTWrite(SST_HANDLE       hFile,
                                  const uint8_t*   pBuffer,
                                  uint32_t         nSize)
{
   TEEC_Session*     pSession;
   TEEC_Result       nError;
   TEEC_Operation    sOperation;
   uint32_t          nReturnOrigin;

   if (pBuffer == NULL)
   {
      return SST_ERROR_BAD_PARAMETERS;
   }

   if (nSize == 0)
   {
      return SST_SUCCESS;
   }

   pSession = static_SSTGetSession();
   if (pSession == NULL)
   {
      return SST_ERROR_GENERIC;
   }

   sOperation.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT, TEEC_MEMREF_TEMP_INPUT, TEEC_NONE, TEEC_NONE);
   sOperation.params[0].value.a       = hFile;
   sOperation.params[1].tmpref.buffer = (void*)pBuffer;
   sOperation.params[1].tmpref.size   = nSize;

   nError = TEEC_InvokeCommand(pSession,
                               SERVICE_SYSTEM_SST_WRITE_COMMAND_ID, /* commandID */
                               &sOperation,                  /* IN OUT operation */
                               &nReturnOrigin            /* OUT returnOrigin, optional */
                              );

   return static_SSTConvertErrorCode(nError);
}


SST_ERROR SST_EXPORT_API SSTRead(SST_HANDLE   hFile,
                                 uint8_t*     pBuffer,
                                 uint32_t     nSize,
                                 uint32_t*    pnCount)
{
   TEEC_Session*     pSession;
   TEEC_Result       nError;
   TEEC_Operation    sOperation;
   uint32_t          nReturnOrigin;

   if ((pBuffer == NULL) || (pnCount == NULL))
   {
      return SST_ERROR_BAD_PARAMETERS;
   }
   *pnCount = 0;

   pSession = static_SSTGetSession();
   if (pSession == NULL)
   {
      return SST_ERROR_GENERIC;
   }

   if (nSize == 0)
   {
      return SST_SUCCESS;
   }

   sOperation.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT, TEEC_MEMREF_TEMP_OUTPUT, TEEC_NONE, TEEC_NONE);
   sOperation.params[0].value.a       = hFile;
   sOperation.params[1].tmpref.buffer = pBuffer;
   sOperation.params[1].tmpref.size   = nSize;

   nError = TEEC_InvokeCommand(pSession,
                               SERVICE_SYSTEM_SST_READ_COMMAND_ID, /* commandID */
                               &sOperation,                  /* IN OUT operation */
                               &nReturnOrigin            /* OUT returnOrigin, optional */
                              );

   *pnCount = sOperation.params[1].tmpref.size; /* The returned buffer size */
   return static_SSTConvertErrorCode(nError);
}

SST_ERROR SST_EXPORT_API SSTSeek(SST_HANDLE   hFile,
                                 int32_t     nOffset,
                                 SST_WHENCE   whence)
{
   TEEC_Session*     pSession;
   TEEC_Result       nError;
   TEEC_Operation    sOperation;
   uint32_t          nReturnOrigin;

   switch(whence)
   {
   case SST_SEEK_SET:
   case SST_SEEK_CUR:
   case SST_SEEK_END:
      break;
   default:
      return SST_ERROR_BAD_PARAMETERS;
   }

   pSession = static_SSTGetSession();
   if (pSession == NULL)
   {
      return SST_ERROR_GENERIC;
   }

   sOperation.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT, TEEC_VALUE_INPUT, TEEC_NONE, TEEC_NONE);
   sOperation.params[0].value.a = hFile;
   sOperation.params[1].value.a = nOffset;
   sOperation.params[1].value.b = (uint32_t)whence;

   nError = TEEC_InvokeCommand(pSession,
                               SERVICE_SYSTEM_SST_SEEK_COMMAND_ID, /* commandID */
                               &sOperation,                  /* IN OUT operation */
                               &nReturnOrigin            /* OUT returnOrigin, optional */
                              );
   return static_SSTConvertErrorCode(nError);

}

static SST_ERROR SSTGetOffsetAndSize(SST_HANDLE   hFile, uint32_t* pnOffset, uint32_t* pnSize)
{
   TEEC_Session*     pSession;
   TEEC_Result       nError;
   TEEC_Operation    sOperation;
   uint32_t          nReturnOrigin;

   pSession = static_SSTGetSession();
   if (pSession == NULL)
   {
      return SST_ERROR_GENERIC;
   }

   if (pnOffset == NULL)
   {
      return SST_ERROR_BAD_PARAMETERS;
   }

   sOperation.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_NONE, TEEC_NONE, TEEC_NONE);
   sOperation.params[0].value.a = (uint32_t)hFile;

   nError = TEEC_InvokeCommand(pSession,
                               SERVICE_SYSTEM_SST_GET_OFFSET_AND_SIZE_COMMAND_ID, /* commandID */
                               &sOperation,                  /* IN OUT operation */
                               &nReturnOrigin            /* OUT returnOrigin, optional */
                              );

   if (pnOffset != NULL)
   {
      *pnOffset = sOperation.params[0].value.a;
   }
   if (pnSize != NULL)
   {
      *pnSize = sOperation.params[0].value.b;
   }
   return static_SSTConvertErrorCode(nError);

}

SST_ERROR SST_EXPORT_API SSTTell(SST_HANDLE   hFile,
                                 uint32_t*    pnPos)
{
   return SSTGetOffsetAndSize(hFile, pnPos, NULL);
}

SST_ERROR SST_EXPORT_API SSTGetSize(const char*  pFilename,
                                    uint32_t*    pnSize)
{
   TEEC_Session*     pSession;
   TEEC_Result       nError;
   TEEC_Operation    sOperation;
   uint32_t          nReturnOrigin;

   if ((pFilename == NULL) || (pnSize == NULL))
   {
      return SST_ERROR_BAD_PARAMETERS;
   }

   nError = static_SSTCheckFileName(pFilename);
   if (nError != SST_SUCCESS)
   {
      return nError;
   }

   pSession = static_SSTGetSession();
   if (pSession == NULL)
   {
      return SST_ERROR_GENERIC;
   }

   sOperation.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_MEMREF_TEMP_INPUT, TEEC_NONE, TEEC_NONE);
   sOperation.params[0].value.a = 1; /* private storage */
   sOperation.params[0].value.b = 0;
   sOperation.params[1].tmpref.buffer = (void*)pFilename;
   sOperation.params[1].tmpref.size   = strlen(pFilename);

   nError = TEEC_InvokeCommand(pSession,
                               SERVICE_SYSTEM_SST_GET_SIZE_COMMAND_ID, /* commandID */
                               &sOperation,                  /* IN OUT operation */
                               &nReturnOrigin            /* OUT returnOrigin, optional */
                              );

   *pnSize = sOperation.params[0].value.a;
   return static_SSTConvertErrorCode(nError);
}


SST_ERROR SST_EXPORT_API SSTEof( SST_HANDLE   hFile,
                                 bool*        pbEof)
{
   uint32_t nOffset;
   uint32_t nSize;
   SST_ERROR nError;
   if (pbEof == NULL)
      return SST_ERROR_BAD_PARAMETERS;
   nError = SSTGetOffsetAndSize(hFile, &nOffset, &nSize);
   if (nError == SST_SUCCESS)
   {
      if (nOffset >= nSize)
      {
         *pbEof = true;
      }
      else
      {
         *pbEof = false;
      }
   }
   return nError;
}

SST_ERROR SST_EXPORT_API SSTCloseAndDelete(SST_HANDLE  hFile)
{
   TEEC_Session*     pSession;
   TEEC_Result       nError;
   TEEC_Operation    sOperation;
   uint32_t          nReturnOrigin;

   pSession = static_SSTGetSession();
   if (pSession == NULL)
   {
      return SST_ERROR_GENERIC;
   }

   sOperation.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT, TEEC_NONE, TEEC_NONE, TEEC_NONE);
   sOperation.params[0].value.a = hFile;

   nError = TEEC_InvokeCommand(pSession,
                               SERVICE_SYSTEM_SST_CLOSE_DELETE_COMMAND_ID, /* commandID */
                               &sOperation,                  /* IN OUT operation */
                               &nReturnOrigin            /* OUT returnOrigin, optional */
                              );
   return static_SSTConvertErrorCode(nError);
}

SST_ERROR SST_EXPORT_API SSTTruncate(SST_HANDLE hFile, uint32_t nLength)
{
   TEEC_Session*     pSession;
   TEEC_Result       nError;
   TEEC_Operation    sOperation;
   uint32_t          nReturnOrigin;

   pSession = static_SSTGetSession();
   if (pSession == NULL)
   {
      return SST_ERROR_GENERIC;
   }

   sOperation.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT, TEEC_NONE, TEEC_NONE, TEEC_NONE);
   sOperation.params[0].value.a = hFile;
   sOperation.params[0].value.b = nLength;

   nError = TEEC_InvokeCommand(pSession,
                               SERVICE_SYSTEM_SST_TRUNCATE_COMMAND_ID, /* commandID */
                               &sOperation,                  /* IN OUT operation */
                               &nReturnOrigin            /* OUT returnOrigin, optional */
                              );
   return static_SSTConvertErrorCode(nError);
}

SST_ERROR SST_EXPORT_API SSTRename(SST_HANDLE hFile,
                                   const char* pNewFilename)
{
   TEEC_Session*     pSession;
   TEEC_Result       nError;
   TEEC_Operation    sOperation;
   uint32_t          nReturnOrigin;

   pSession = static_SSTGetSession();
   if (pSession == NULL)
   {
      return SST_ERROR_GENERIC;
   }

   if (pNewFilename == NULL)
   {
      return SST_ERROR_BAD_PARAMETERS;
   }

   nError = static_SSTCheckFileName(pNewFilename);
   if (nError != SST_SUCCESS)
   {
      return nError;
   }

   sOperation.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT, TEEC_MEMREF_TEMP_INPUT, TEEC_NONE, TEEC_NONE);
   sOperation.params[0].value.a = hFile;
   sOperation.params[1].tmpref.buffer = (void*)pNewFilename;
   sOperation.params[1].tmpref.size   = strlen(pNewFilename);

   nError = TEEC_InvokeCommand(pSession,
                               SERVICE_SYSTEM_SST_RENAME_COMMAND_ID, /* commandID */
                               &sOperation,                  /* IN OUT operation */
                               &nReturnOrigin            /* OUT returnOrigin, optional */
                              );
      return static_SSTConvertErrorCode(nError);
}

SST_ERROR SST_EXPORT_API SSTEnumerationStart(const char* pFilenamePattern,
                                             uint32_t  nReserved1,
                                             uint32_t  nReserved2,
                                             SST_HANDLE* phFileEnumeration)
{
   TEEC_Session*     pSession;
   TEEC_Result       nError;
   TEEC_Operation    sOperation;
   uint32_t          nReturnOrigin;

   if (nReserved1!=0 || nReserved2!=0)
   {
      return SST_ERROR_BAD_PARAMETERS;
   }
   if (phFileEnumeration==NULL)
   {
      return SST_ERROR_BAD_PARAMETERS;
   }
   *phFileEnumeration = SST_HANDLE_INVALID;

   nError = static_SSTCheckPattern(pFilenamePattern);
   if (nError != SST_SUCCESS)
   {
      return nError;
   }

   pSession = static_SSTGetSession();
   if (pSession == NULL)
   {
      return SST_ERROR_GENERIC;
   }

   sOperation.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_MEMREF_TEMP_INPUT, TEEC_NONE, TEEC_NONE);
   sOperation.params[0].value.a = 1;      /* Private storage */
   sOperation.params[1].tmpref.buffer = (void*)pFilenamePattern;
   if (pFilenamePattern != NULL)
   {
      sOperation.params[1].tmpref.size   = strlen(pFilenamePattern);
   }
   else
   {
      sOperation.params[1].tmpref.size   = 0;
   }

   nError = TEEC_InvokeCommand(pSession,
                               SERVICE_SYSTEM_SST_ENUM_START_COMMAND_ID, /* commandID */
                               &sOperation,                  /* IN OUT operation */
                               &nReturnOrigin            /* OUT returnOrigin, optional */
                              );

   *phFileEnumeration = (SST_HANDLE)sOperation.params[0].value.a;
   return static_SSTConvertErrorCode(nError);
}

SST_ERROR SST_EXPORT_API SSTEnumerationCloseHandle(SST_HANDLE hFileEnumeration)
{
   TEEC_Session*     pSession;
   TEEC_Result       nError;
   TEEC_Operation    sOperation;
   uint32_t          nReturnOrigin;

   pSession = static_SSTGetSession();
   if (pSession == NULL)
   {
      return SST_ERROR_GENERIC;
   }

   sOperation.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT, TEEC_NONE, TEEC_NONE, TEEC_NONE);
   sOperation.params[0].value.a = hFileEnumeration;

   nError = TEEC_InvokeCommand(pSession,
                               SERVICE_SYSTEM_SST_ENUM_CLOSE_COMMAND_ID, /* commandID */
                               &sOperation,                  /* IN OUT operation */
                               &nReturnOrigin                /* OUT returnOrigin, optional */
                              );

   return static_SSTConvertErrorCode(nError);
}

SST_ERROR SST_EXPORT_API SSTEnumerationGetNext(SST_HANDLE      hFileEnumeration,
                                               SST_FILE_INFO**   ppFileInfo)

{
   TEEC_Session*     pSession;
   TEEC_Result       nError;
   TEEC_Operation    sOperation;
   uint32_t          nReturnOrigin;
   SST_FILE_INFO*    pInfo = NULL;
   char              sFilename[SST_MAX_FILENAME];

   if (ppFileInfo==NULL)
   {
      return SST_ERROR_BAD_PARAMETERS;
   }

   pSession = static_SSTGetSession();
   if (pSession == NULL)
   {
      return SST_ERROR_GENERIC;
   }

   sOperation.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_MEMREF_TEMP_OUTPUT, TEEC_NONE, TEEC_NONE);
   sOperation.params[0].value.a = hFileEnumeration;
   sOperation.params[1].tmpref.buffer = sFilename;
   sOperation.params[1].tmpref.size   = SST_MAX_FILENAME;

   nError = TEEC_InvokeCommand(pSession,
                               SERVICE_SYSTEM_SST_ENUM_GETNEXT_COMMAND_ID, /* commandID */
                               &sOperation,                  /* IN OUT operation */
                               &nReturnOrigin            /* OUT returnOrigin, optional */
                              );

   if (nError == TEEC_SUCCESS)
   {
      if (sOperation.params[1].tmpref.size <= SST_MAX_FILENAME)
      {
         pInfo = (SST_FILE_INFO*)malloc(sizeof(SST_FILE_INFO));
         if (pInfo == NULL)
         {
            return SST_ERROR_OUT_OF_MEMORY;
         }
         pInfo->pName = (char*)malloc(sOperation.params[1].tmpref.size+1);
         if (pInfo->pName == NULL)
         {
            free(pInfo);
            return SST_ERROR_OUT_OF_MEMORY;
         }
         memcpy(pInfo->pName, sFilename, sOperation.params[1].tmpref.size);
         /* Add zero terminator */
         pInfo->pName[sOperation.params[1].tmpref.size] = 0;
         pInfo->nSize = sOperation.params[0].value.b;
      }
   }
  *ppFileInfo = pInfo;
   return static_SSTConvertErrorCode(nError);
 }

SST_ERROR SST_EXPORT_API SSTDestroyFileInfo(SST_FILE_INFO*   pFileInfo)
{
   TEEC_Session*  pSession;

   pSession = static_SSTGetSession();
   if (pSession == NULL)
   {
      return SST_ERROR_GENERIC;
   }

   if (pFileInfo != NULL)
   {
      free(pFileInfo->pName);
      free(pFileInfo);
   }
   return SST_SUCCESS;
}