diff options
Diffstat (limited to 'source/LCDriver.cpp')
-rw-r--r-- | source/LCDriver.cpp | 595 |
1 files changed, 595 insertions, 0 deletions
diff --git a/source/LCDriver.cpp b/source/LCDriver.cpp new file mode 100644 index 0000000..9ce9c25 --- /dev/null +++ b/source/LCDriver.cpp @@ -0,0 +1,595 @@ +/******************************************************************************* + * Copyright (C) ST-Ericsson SA 2011 + * License terms: 3-clause BSD license + ******************************************************************************/ + +#include "LCDriver.h" +#include "lcdriver_error_codes.h" +#include "LCDriverInterface.h" +#include "Error.h" + +#define VERIFY_CONTEXT(c) \ + do { \ + if ((c) == NULL) \ + return INTERFACE_OBJECT_POINTER_NULL; \ + if ((c)->m_pObject == NULL) \ + return INTERFACE_LC_METHODS_OBJECT_NULL; \ + } while (0) + +#define VERIFY_CONTEXT_STARTED(c) \ + do { \ + VERIFY_CONTEXT(c); \ + if (!(c)->isStarted) \ + return INTERFACE_CONTEXT_NOT_STARTED; \ + } while (0) + +/************************************************************************************************ +* API functions for LCDriver functionalities +************************************************************************************************/ +LCDRIVER_API int __cdecl Initialize(LCDContext *pContext, const char *InterfaceId, void *Read_fn, void *Write_fn, void *Cancel_fn, void **Instance, void *Message_fn, const char *LCMLibPath, void *ProgressBar_fn) +{ + SetLCMLibPath(LCMLibPath); + + int Result = CreateContext(pContext, InterfaceId); + + if (0 != Result) { + return Result; + } + + // check if we have context that was previously started + if (!(*pContext)->isStarted) { + ConfigureCommunicationDevice(*pContext, Read_fn, Write_fn, Cancel_fn); + SwitchProtocolFamily(*pContext, R15_PROTOCOL_FAMILY); + SetMessageCallback(*pContext, Message_fn); + SetProgressCallback(*pContext, ProgressBar_fn); + + return StartContext(*pContext, Instance); + } else { + return 0; + } +} + +LCDRIVER_API void __cdecl SetLCMLibPath(const char *LCMLibPath) +{ + LcmInterface::SetLCMLibPath(LCMLibPath); +} + +LCDRIVER_API int __cdecl CreateContext(LCDContext *pContext, const char *InterfaceId) +{ + CLockCS CsLock(CLCDriverInterface::InitializationCS); + + CLCDriverInterface *Context = NULL; + int ReturnValue = E_SUCCESS; + + // Check pointer to pointer + VERIFY(NULL != pContext, INTERFACE_OBJECT_POINTER_TO_POINTER_NULL); + + // Check if CLCDriverInterface already exists + VERIFY(NULL == *pContext, INTERFACE_OBJECT_ALREADY_EXISTS); + + // Check context id + VERIFY(NULL != InterfaceId, INTERFACE_INTERFACEID_POINTER_NULL); + + // Create new CLCDriverInterface + Context = new CLCDriverInterface(); + VERIFY(NULL != Context, INTERFACE_COULD_NOT_CREATE_IFC_OBJECT); + + strcpy_s(Context->m_szObjectId, InterfaceId); + + // Check in the object list if this particular object has been created earlier. + Context->m_pObject = CLCDriverInterface::FindObject(Context->m_szObjectId); + + // An object was found in the list + if (Context->m_pObject == NULL) { + // Create new CLCDriverMethods + Context->m_pObject = new CLCDriverMethods(InterfaceId); + VERIFY(NULL != Context->m_pObject, INTERFACE_COULD_NOT_CREATE_OBJECT); + } + + // Add the object to the list to increase the reference counter + ReturnValue = CLCDriverInterface::AddObject(Context->m_pObject, Context->m_szObjectId); + VERIFY(0 == ReturnValue, INTERFACE_COULD_NOT_ADD_OBJECT_TO_LIST); + + *pContext = Context; + + return E_SUCCESS; +ErrorExit: + + // Delete the CLCDriverInterface + if (Context != NULL) { + if (Context->m_pObject != NULL) { + delete Context->m_pObject; + Context->m_pObject = NULL; + } + + delete Context; + } + + return ReturnValue; +} + +LCDRIVER_API int __cdecl SwitchProtocolFamily(LCDContext Context, TFamily Family) +{ + VERIFY_CONTEXT(Context); + + if (Context->isStarted) { + return Context->m_pObject->Do_SwitchProtocolFamily(Family); + } else { + return Context->m_pObject->SetInitialProtocolFamily(Family); + } +} + +LCDRIVER_API int __cdecl ConfigureCommunicationDevice(LCDContext Context, void *Read_fn, void *Write_fn, void *Cancel_fn) +{ + VERIFY_CONTEXT(Context); + + Context->m_pObject->ConfigureCommunicationDevice(Read_fn, Write_fn, Cancel_fn); + return 0; +} + +LCDRIVER_API int __cdecl SetMessageCallback(LCDContext Context, void *Callback_fn) +{ + VERIFY_CONTEXT(Context); + + Context->m_pObject->SetMessageCallback(Callback_fn); + return 0; +} + +LCDRIVER_API int __cdecl SetProgressCallback(LCDContext Context, void *Callback_fn) +{ + VERIFY_CONTEXT(Context); + + Context->m_pObject->SetProgressCallback(Callback_fn); + return 0; +} + +LCDRIVER_API int __cdecl StartContext(LCDContext Context, void **Instance) +{ + VERIFY_CONTEXT(Context); + + int Result = Context->m_pObject->Do_Initialize(Instance); + + if (0 == Result) { + Context->isStarted = true; + } + + return Result; +} + +LCDRIVER_API int __cdecl DestroyContext(LCDContext *pContext) +{ + LCDContext Context = *pContext; + VERIFY_CONTEXT(Context); + + delete Context; + *pContext = NULL; + + return 0; +} + +LCDRIVER_API int __cdecl Close(LCDContext Context) +{ + return DestroyContext(&Context); +} + +LCDRIVER_API int __cdecl SetTimeouts(LCDContext Context, TR15Timeouts *R15_TOs, TLCDriverTimeouts *LCD_TOs) +{ + VERIFY_CONTEXT(Context); + + return Context->m_pObject->SetPcTimeouts(R15_TOs, LCD_TOs); +} + +LCDRIVER_API int __cdecl GetTimeouts(LCDContext Context, TR15Timeouts *R15_TOs, TLCDriverTimeouts *LCD_TOs) +{ + VERIFY_CONTEXT(Context); + + return Context->m_pObject->GetPcTimeouts(R15_TOs, LCD_TOs); +} + +LCDRIVER_API int __cdecl CancelCurrentLoaderCommand(LCDContext Context) +{ + VERIFY_CONTEXT(Context); + + Context->m_pObject->CancelCurrentLoaderCommand(); + + return 0; +} + +/************************************************************************************************ +* API functions for loader commands +************************************************************************************************/ +LCDRIVER_API int __cdecl System_LoaderStartupStatus(LCDContext Context, char *pchVersion, int *piVersionSize, char *pchProtocol, int *piProtocolSize) +{ + VERIFY_CONTEXT_STARTED(Context); + + return Context->m_pObject->Done_System_LoaderStartupStatus(pchVersion, piVersionSize, pchProtocol, piProtocolSize); +} + +LCDRIVER_API int __cdecl System_Reboot(LCDContext Context, int iMode) +{ + VERIFY_CONTEXT_STARTED(Context); + + return Context->m_pObject->Do_System_Reboot(iMode); +} + +LCDRIVER_API int __cdecl System_Shutdown(LCDContext Context) +{ + VERIFY_CONTEXT_STARTED(Context); + + return Context->m_pObject->Do_System_Shutdown(); +} + +LCDRIVER_API int __cdecl System_SupportedCommands(LCDContext Context, TSupportedCmd *pCmdList, int *piCmdListSize) +{ + VERIFY_CONTEXT_STARTED(Context); + + return Context->m_pObject->Do_System_SupportedCommands(pCmdList, piCmdListSize); +} + +LCDRIVER_API int __cdecl System_CollectData(LCDContext Context, int iType, int *piSize, char *pData) +{ + VERIFY_CONTEXT_STARTED(Context); + + return Context->m_pObject->Do_System_CollectData(iType, piSize, pData); +} + +LCDRIVER_API int __cdecl System_ExecuteSoftware(LCDContext Context, const uint32 ExecuteMode, const char *pchDevicePath, int iUseBulk) +{ + VERIFY_CONTEXT_STARTED(Context); + + return Context->m_pObject->Do_System_ExecuteSoftware(ExecuteMode, pchDevicePath, iUseBulk); +} + +LCDRIVER_API int __cdecl System_Authenticate(LCDContext Context, int iType, int *piSize, unsigned char *puchdata) +{ + VERIFY_CONTEXT_STARTED(Context); + + return Context->m_pObject->Do_System_Authenticate(iType, piSize, puchdata); +} + +LCDRIVER_API int __cdecl System_GetControlKeys(LCDContext Context, TSIMLockKeys *pSIMLockKeys) +{ + VERIFY_CONTEXT_STARTED(Context); + + return Context->m_pObject->Done_System_GetControlKeys(pSIMLockKeys); +} + +LCDRIVER_API int __cdecl System_GetControlKeysData(LCDContext Context, int iDataSize, unsigned char *pSIMLockKeysData) +{ + VERIFY_CONTEXT_STARTED(Context); + + return Context->m_pObject->Done_System_GetControlKeysData(iDataSize, pSIMLockKeysData); +} + +LCDRIVER_API int __cdecl System_AuthenticationChallenge(LCDContext Context, unsigned char *puchChallengeData, int iDataSize) +{ + VERIFY_CONTEXT_STARTED(Context); + + return Context->m_pObject->Done_System_AuthenticationChallenge(iDataSize, puchChallengeData); +} + +LCDRIVER_API int __cdecl System_SetSystemTime(LCDContext Context, uint32 uiEpochTime) +{ + VERIFY_CONTEXT_STARTED(Context); + + return Context->m_pObject->Do_System_SetSystemTime(uiEpochTime); +} + +LCDRIVER_API int __cdecl System_SwitchCommunicationDevice(LCDContext Context, uint32 uiDevice, uint32 uiDeviceParam) +{ + VERIFY_CONTEXT_STARTED(Context); + + return Context->m_pObject->Do_System_SwitchCommunicationDevice(uiDevice, uiDevice); +} + +LCDRIVER_API int __cdecl Flash_ProcessFile(LCDContext Context, const char *pchPath, const char *pchType, int iUseBulk, int iDeleteBuffers) +{ + VERIFY_CONTEXT_STARTED(Context); + + return Context->m_pObject->Do_Flash_ProcessFile(pchPath, pchType, iUseBulk, iDeleteBuffers); +} + +LCDRIVER_API int __cdecl Flash_ListDevices(LCDContext Context, TDevices *pDevices, int *piDeviceSize) +{ + VERIFY_CONTEXT_STARTED(Context); + + return Context->m_pObject->Do_Flash_ListDevices(pDevices, piDeviceSize); +} + +LCDRIVER_API int __cdecl Flash_DumpArea(LCDContext Context, const char *pchPathToDump, uint64 uiStart, uint64 uiLength, const char *pchFilePath, uint32 uiRedundantArea, int iUseBulk) +{ + VERIFY_CONTEXT_STARTED(Context); + + return Context->m_pObject->Do_Flash_DumpArea(pchPathToDump, uiStart, uiLength, pchFilePath, uiRedundantArea, iUseBulk); +} + +LCDRIVER_API int __cdecl Flash_EraseArea(LCDContext Context, const char *pchPath, uint64 uiStart, uint64 uiLength) +{ + VERIFY_CONTEXT_STARTED(Context); + + return Context->m_pObject->Do_Flash_EraseArea(pchPath, uiStart, uiLength); +} + +LCDRIVER_API int __cdecl Flash_FlashRaw(LCDContext Context, const char *pchPath, uint64 uiStart, uint64 uiLength, uint32 uiDevice, int iUseBulk, int iDeleteBuffers) +{ + VERIFY_CONTEXT_STARTED(Context); + + return Context->m_pObject->Do_Flash_FlashRaw(pchPath, uiStart, uiLength, uiDevice, iUseBulk, iDeleteBuffers); +} + +LCDRIVER_API int __cdecl FileSystem_VolumeProperties(LCDContext Context, const char *pchDevicePath, char *pchFSType, int *piFSTypeSize, uint64 *puiSize, uint64 *puiFree) +{ + VERIFY_CONTEXT_STARTED(Context); + + return Context->m_pObject->Do_FileSystem_VolumeProperties(pchDevicePath, pchFSType, piFSTypeSize, puiSize, puiFree); +} + +LCDRIVER_API int __cdecl FileSystem_FormatVolume(LCDContext Context, const char *pchDevicePath) +{ + VERIFY_CONTEXT_STARTED(Context); + + return Context->m_pObject->Do_FileSystem_FormatVolume(pchDevicePath); +} + +LCDRIVER_API int __cdecl FileSystem_ListDirectory(LCDContext Context, const char *pchPath, TEntries *pEntries, int *piDeviceSize) +{ + VERIFY_CONTEXT_STARTED(Context); + + return Context->m_pObject->Do_FileSystem_ListDirectory(pchPath, pEntries, piDeviceSize); +} + +LCDRIVER_API int __cdecl FileSystem_MoveFile(LCDContext Context, const char *pchSourcePath, const char *pchDestinationPath) +{ + VERIFY_CONTEXT_STARTED(Context); + + return Context->m_pObject->Do_FileSystem_MoveFile(pchSourcePath, pchDestinationPath); +} + +LCDRIVER_API int __cdecl FileSystem_DeleteFile(LCDContext Context, const char *pchTargetPath) +{ + VERIFY_CONTEXT_STARTED(Context); + + return Context->m_pObject->Do_FileSystem_DeleteFile(pchTargetPath); +} + +LCDRIVER_API int __cdecl FileSystem_CopyFile(LCDContext Context, const char *pchSourcePath, int iSourceUseBulk, const char *pchDestinationPath, int iDestinationUseBulk) +{ + VERIFY_CONTEXT_STARTED(Context); + + return Context->m_pObject->Do_FileSystem_CopyFile(pchSourcePath, iSourceUseBulk, pchDestinationPath, iDestinationUseBulk); +} + +LCDRIVER_API int __cdecl FileSystem_CreateDirectory(LCDContext Context, const char *pchTargetPath) +{ + VERIFY_CONTEXT_STARTED(Context); + + return Context->m_pObject->Do_FileSystem_CreateDirectory(pchTargetPath); +} + +LCDRIVER_API int __cdecl FileSystem_Properties(LCDContext Context, const char *pchTargetPath, uint32 *puiMode, uint64 *puiSize, int *piMTime, int *piATime, int *piCTime) +{ + VERIFY_CONTEXT_STARTED(Context); + + return Context->m_pObject->Do_FileSystem_Properties(pchTargetPath, puiMode, puiSize, piMTime, piATime, piCTime); +} + +LCDRIVER_API int __cdecl FileSystem_ChangeAccess(LCDContext Context, const char *pchTargetPath, int iAccess) +{ + VERIFY_CONTEXT_STARTED(Context); + + return Context->m_pObject->Do_FileSystem_ChangeAccess(pchTargetPath, iAccess); +} + +LCDRIVER_API int __cdecl FileSystem_ReadLoadModuleManifests(LCDContext Context, const char *pchTargetPath, const char *pchSourcePath) +{ + VERIFY_CONTEXT_STARTED(Context); + + return Context->m_pObject->Do_FileSystem_ReadLoadModuleManifests(pchTargetPath, pchSourcePath); +} + +LCDRIVER_API int __cdecl OTP_ReadBits(LCDContext Context, int iOtpId, int iBitStart, int iBitLength, unsigned char *puchDataBuffer, int *piDataBufferSize, unsigned char *puchStatusBuffer, int *piStatusBufferSize) +{ + VERIFY_CONTEXT_STARTED(Context); + + return Context->m_pObject->Do_OTP_ReadBits(iOtpId, iBitStart, iBitLength, puchDataBuffer, piDataBufferSize, puchStatusBuffer, piStatusBufferSize); +} + +LCDRIVER_API int __cdecl OTP_SetBits(LCDContext Context, int iOtpId, int iBitStart, int iBitLength, unsigned char *puchDataBuffer) +{ + VERIFY_CONTEXT_STARTED(Context); + + return Context->m_pObject->Do_OTP_SetBits(iOtpId, iBitStart, iBitLength, puchDataBuffer); +} + +LCDRIVER_API int __cdecl OTP_WriteAndLock(LCDContext Context, int iOtpId, int iForceWrite) +{ + VERIFY_CONTEXT_STARTED(Context); + + return Context->m_pObject->Do_OTP_WriteAndLock(iOtpId, iForceWrite); +} + +LCDRIVER_API int __cdecl ParameterStorage_ReadGlobalDataUnit(LCDContext Context, const char *pchGdfsId, int iUnit, unsigned char *puchDataBuffer, int *piSize) +{ + VERIFY_CONTEXT_STARTED(Context); + + return Context->m_pObject->Do_ParameterStorage_ReadGlobalDataUnit(pchGdfsId, iUnit, puchDataBuffer, piSize); +} + +LCDRIVER_API int __cdecl ParameterStorage_WriteGlobalDataUnit(LCDContext Context, const char *pchGdfsId, int iUnit, unsigned char *puchDataBuffer, int iSize) +{ + VERIFY_CONTEXT_STARTED(Context); + + return Context->m_pObject->Do_ParameterStorage_WriteGlobalDataUnit(pchGdfsId, iUnit, puchDataBuffer, iSize); +} + +LCDRIVER_API int __cdecl ParameterStorage_ReadGlobalDataSet(LCDContext Context, const char *pchGdfsId, const char *pchPath, int iUseBulk) +{ + VERIFY_CONTEXT_STARTED(Context); + + return Context->m_pObject->Do_ParameterStorage_ReadGlobalDataSet(pchGdfsId, pchPath, iUseBulk); +} + +LCDRIVER_API int __cdecl ParameterStorage_WriteGlobalDataSet(LCDContext Context, const char *pchGdfsId, const char *pchPath, int iUseBulk) +{ + VERIFY_CONTEXT_STARTED(Context); + + return Context->m_pObject->Do_ParameterStorage_WriteGlobalDataSet(pchGdfsId, pchPath, iUseBulk); +} + +LCDRIVER_API int __cdecl ParameterStorage_EraseGlobalDataSet(LCDContext Context, const char *pchGdfsId) +{ + VERIFY_CONTEXT_STARTED(Context); + + return Context->m_pObject->Do_ParameterStorage_EraseGlobalDataSet(pchGdfsId); +} + +LCDRIVER_API int __cdecl Security_SetDomain(LCDContext Context, int iDomain) +{ + VERIFY_CONTEXT_STARTED(Context); + + return Context->m_pObject->Do_Security_SetDomain(iDomain); +} + +LCDRIVER_API int __cdecl Security_GetDomain(LCDContext Context, int *piWrittenDomain) +{ + VERIFY_CONTEXT_STARTED(Context); + + return Context->m_pObject->Do_Security_GetDomain(piWrittenDomain); +} + +LCDRIVER_API int __cdecl Security_GetProperties(LCDContext Context, int iUnitId, int *piSize, unsigned char *puchDataBuffer) +{ + VERIFY_CONTEXT_STARTED(Context); + + return Context->m_pObject->Do_Security_GetProperties(iUnitId, piSize, puchDataBuffer); +} + +LCDRIVER_API int __cdecl Security_SetProperties(LCDContext Context, int iUnitId, int iSize, unsigned char *puchDataBuffer) +{ + VERIFY_CONTEXT_STARTED(Context); + + return Context->m_pObject->Do_Security_SetProperties(iUnitId, iSize, puchDataBuffer); +} + +LCDRIVER_API int __cdecl Security_BindProperties(LCDContext Context) +{ + VERIFY_CONTEXT_STARTED(Context); + + return Context->m_pObject->Do_Security_BindProperties(); +} + +LCDRIVER_API int __cdecl Security_StoreSecureObject(LCDContext Context, const char *pchSourcePath, int iDestination, int iUseBulk) +{ + VERIFY_CONTEXT_STARTED(Context); + + return Context->m_pObject->Do_OTP_StoreSecureObject(pchSourcePath, iDestination, iUseBulk); +} + +LCDRIVER_API int __cdecl A2_System_Shutdown(LCDContext Context) +{ + VERIFY_CONTEXT_STARTED(Context); + + return Context->m_pObject->Do_A2_System_Shutdown(); +} + +LCDRIVER_API int __cdecl A2_System_LoaderVersion(LCDContext Context, char *pchLoaderVersion, int *piSize, int iTargetCPU) +{ + VERIFY_CONTEXT_STARTED(Context); + + return Context->m_pObject->Do_A2_System_LoaderVersion(pchLoaderVersion, piSize, iTargetCPU); +} + +LCDRIVER_API int __cdecl A2_System_LoaderOnLoader(LCDContext Context, const char *pchPath, int iPLOffset, int iHLOffset, int iTargetCPU) +{ + VERIFY_CONTEXT_STARTED(Context); + + return Context->m_pObject->Do_A2_System_LoaderOnLoader(pchPath, iPLOffset, iHLOffset, iTargetCPU); +} + +LCDRIVER_API int __cdecl A2_System_Reset(LCDContext Context, int iTimeout) +{ + VERIFY_CONTEXT_STARTED(Context); + + return Context->m_pObject->Do_A2_System_Reset(iTimeout); +} + +LCDRIVER_API int __cdecl A2_Flash_ProgramFlash(LCDContext Context, const char *pchPath, int iUseSpeedFlash) +{ + VERIFY_CONTEXT_STARTED(Context); + + return Context->m_pObject->Do_A2_Flash_ProgramFlash(pchPath, iUseSpeedFlash); +} + +LCDRIVER_API int __cdecl A2_Flash_EraseFlash(LCDContext Context) +{ + VERIFY_CONTEXT_STARTED(Context); + + return Context->m_pObject->Do_A2_Flash_EraseFlash(); +} + +LCDRIVER_API int __cdecl A2_Control_LoaderStarted(LCDContext Context) +{ + VERIFY_CONTEXT_STARTED(Context); + + return Context->m_pObject->Done_A2_Control_LoaderStarted(); +} + +LCDRIVER_API int __cdecl SetProtocolFamily(LCDContext Context, const char *pchFamily) +{ + VERIFY_CONTEXT_STARTED(Context); + + TFamily newFamily; + + if (0 == strcmp(pchFamily, "R15_FAMILY")) { + newFamily = R15_PROTOCOL_FAMILY; + } else if (0 == strcmp(pchFamily, "PROTROM_FAMILY")) { + newFamily = PROTROM_PROTOCOL_FAMILY; + } else if (0 == strcmp(pchFamily, "NOPROT")) { + newFamily = Z_PROTOCOL_FAMILY; + } else if (0 == strcmp(pchFamily, "A2_FAMILY")) { + newFamily = A2_PROTOCOL_FAMILY; + } else { + return INVALID_INPUT_PARAMETERS; + } + + return Context->m_pObject->Do_SwitchProtocolFamily(newFamily); +} + +LCDRIVER_API int __cdecl Z_SetInServiceMode(LCDContext Context, unsigned int *puiChipId) +{ + VERIFY_CONTEXT_STARTED(Context); + + return Context->m_pObject->Do_Z_SetInServiceMode(puiChipId); +} + +LCDRIVER_API int __cdecl Z_SetBaudrate(LCDContext Context, int iBaudrate) +{ + VERIFY_CONTEXT_STARTED(Context); + + return Context->m_pObject->Do_Z_SetBaudrate(iBaudrate); +} + +LCDRIVER_API int __cdecl Z_Exit_Z_Protocol(LCDContext Context) +{ + VERIFY_CONTEXT_STARTED(Context); + + return Context->m_pObject->Do_Z_Exit_Z_Protocol(); +} + +LCDRIVER_API int __cdecl PROTROM_DownloadLoader(LCDContext Context, const char *pchPath, int iPLOffset, int iHLOffset, int iContinueProtRom) +{ + VERIFY_CONTEXT_STARTED(Context); + + return Context->m_pObject->Do_PROTROM_DownloadLoader(pchPath, iPLOffset, iHLOffset, iContinueProtRom); +} + +LCDRIVER_API int __cdecl PROTROM_ReadSecurityData(LCDContext Context, unsigned char uiSecDataId, unsigned char *puchDataBuffer, int *piDataLength) +{ + VERIFY_CONTEXT_STARTED(Context); + + if (NULL == puchDataBuffer || 0 == piDataLength) { + return INVALID_INPUT_PARAMETERS; + } + + return Context->m_pObject->Do_PROTROM_ReadSecurityData(uiSecDataId, puchDataBuffer, piDataLength); +} |