os/security/cryptoservices/filebasedcertificateandkeystores/test/certtool/certtool.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
sl@0
     1
/*
sl@0
     2
* Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies).
sl@0
     3
* All rights reserved.
sl@0
     4
* This component and the accompanying materials are made available
sl@0
     5
* under the terms of the License "Eclipse Public License v1.0"
sl@0
     6
* which accompanies this distribution, and is available
sl@0
     7
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0
     8
*
sl@0
     9
* Initial Contributors:
sl@0
    10
* Nokia Corporation - initial contribution.
sl@0
    11
*
sl@0
    12
* Contributors:
sl@0
    13
*
sl@0
    14
* Description: 
sl@0
    15
*
sl@0
    16
*/
sl@0
    17
sl@0
    18
sl@0
    19
#include <e32cons.h>
sl@0
    20
#include <bacline.h>
sl@0
    21
sl@0
    22
#include "keytool_utils.h"
sl@0
    23
#include "keytool_view_imp.h"
sl@0
    24
#include "keytool_commands.h"
sl@0
    25
#include "certtool_controller.h"
sl@0
    26
#include "keytoolfileview.h"
sl@0
    27
sl@0
    28
sl@0
    29
// Boiler plate 
sl@0
    30
_LIT(KShortName, "Symbian OS CertTool");
sl@0
    31
_LIT(KName, "Symbian OS CertStore Manipulation Tool");
sl@0
    32
_LIT(KCopyright, "Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies).  All rights reserved.");
sl@0
    33
sl@0
    34
_LIT(KNewLine, "\n");
sl@0
    35
sl@0
    36
_LIT(KDone, "Press any key to continue... \n");
sl@0
    37
sl@0
    38
// CertTool command line parameters
sl@0
    39
sl@0
    40
_LIT(KList, "-list");
sl@0
    41
_LIT(KListShort, "-l");
sl@0
    42
sl@0
    43
_LIT(KListStores, "-liststores");
sl@0
    44
_LIT(KListStoresShort, "-ls");
sl@0
    45
sl@0
    46
_LIT(KImport, "-import");
sl@0
    47
_LIT(KImportShort, "-i");
sl@0
    48
sl@0
    49
_LIT(KPrivate, "-private");
sl@0
    50
sl@0
    51
sl@0
    52
_LIT(KSetApps, "-setapps");
sl@0
    53
_LIT(KSetAppsShort, "-s");
sl@0
    54
sl@0
    55
_LIT(KAddApps, "-addapps");
sl@0
    56
_LIT(KAddAppsShort, "-a");
sl@0
    57
sl@0
    58
_LIT(KApps, "-apps");
sl@0
    59
sl@0
    60
_LIT(KRemoveApps, "-removeapps");
sl@0
    61
sl@0
    62
_LIT(KRemove, "-remove");
sl@0
    63
_LIT(KRemoveShort, "-r");
sl@0
    64
sl@0
    65
// remove private key also while removing the certificate
sl@0
    66
// which is applicable iff the key is imported using the certool -private option
sl@0
    67
sl@0
    68
_LIT(KRemoveKeyAlso, "-rka");
sl@0
    69
sl@0
    70
_LIT(KStore, "-store");
sl@0
    71
sl@0
    72
_LIT(KHelp, "-help");
sl@0
    73
_LIT(KHelpShort, "-h");
sl@0
    74
sl@0
    75
// Command parameters
sl@0
    76
_LIT(KLabel, "-label");
sl@0
    77
sl@0
    78
_LIT(KDetails, "-details");
sl@0
    79
_LIT(KDetailsShort, "-d");
sl@0
    80
sl@0
    81
_LIT(KOwnerType, "-owner");
sl@0
    82
_LIT(KOwnerTypeShort, "-o");
sl@0
    83
sl@0
    84
_LIT(KPageWise, "-page");
sl@0
    85
_LIT(KPageWiseShort, "-p");
sl@0
    86
sl@0
    87
_LIT(KUids, "-uids");
sl@0
    88
sl@0
    89
_LIT(KDeletable, "-deletable");
sl@0
    90
_LIT(KDeletableShort, "-del");
sl@0
    91
sl@0
    92
const TInt KMaxArgs = 10;
sl@0
    93
sl@0
    94
/**
sl@0
    95
 * Certtool can operate in the following modes.
sl@0
    96
**/
sl@0
    97
enum OperationMode {
sl@0
    98
Interactive,
sl@0
    99
NonInteractive
sl@0
   100
};
sl@0
   101
sl@0
   102
sl@0
   103
/**
sl@0
   104
 * Displays tool name and copy-right informations.
sl@0
   105
 */
sl@0
   106
LOCAL_D void BoilerPlateL(CConsoleBase* console) 
sl@0
   107
	{
sl@0
   108
	console->Printf(KNewLine);
sl@0
   109
	console->Printf(KName);
sl@0
   110
	console->Printf(KNewLine);	
sl@0
   111
	console->Printf(KCopyright);
sl@0
   112
	console->Printf(KNewLine);
sl@0
   113
	console->Printf(KNewLine);	
sl@0
   114
	}
sl@0
   115
sl@0
   116
LOCAL_D TBool VerifyCommand(const TDesC& aCommand, TInt& aCmdNum, TInt& aCmdCount)
sl@0
   117
	{
sl@0
   118
	if ((aCmdNum != -1) && (aCommand[0] == '-'))
sl@0
   119
		{
sl@0
   120
		aCmdNum = CertToolDefController::KUsageCommand;
sl@0
   121
		aCmdCount = KMaxArgs;
sl@0
   122
		return 1;
sl@0
   123
		}
sl@0
   124
	if (aCommand.CompareF(KList) == 0 || aCommand.Compare(KListShort) == 0)
sl@0
   125
		{
sl@0
   126
		aCmdNum = CertToolDefController::KListCommand;
sl@0
   127
		}
sl@0
   128
	else if (aCommand.CompareF(KListStores) == 0 || aCommand.Compare(KListStoresShort) == 0)
sl@0
   129
		{
sl@0
   130
		aCmdNum = CertToolDefController::KListStoresCommand;
sl@0
   131
		}
sl@0
   132
	else if	(aCommand.CompareF(KImport) == 0 || aCommand.Compare(KImportShort) == 0)
sl@0
   133
		{
sl@0
   134
		aCmdNum = CertToolDefController::KImportCommand;
sl@0
   135
		}
sl@0
   136
	else if	(aCommand.CompareF(KRemove) == 0 || aCommand.Compare(KRemoveShort) == 0)
sl@0
   137
		{
sl@0
   138
		aCmdNum = CertToolDefController::KRemoveCommand;
sl@0
   139
		}
sl@0
   140
	else if	(aCommand.CompareF(KSetApps) == 0 || aCommand.Compare(KSetAppsShort) == 0)
sl@0
   141
		{
sl@0
   142
		aCmdNum = CertToolDefController::KSetAppsCommand;
sl@0
   143
		}
sl@0
   144
	else if	(aCommand.CompareF(KAddApps) == 0 || aCommand.Compare(KAddAppsShort) == 0)
sl@0
   145
		{
sl@0
   146
		aCmdNum = CertToolDefController::KAddAppsCommand;
sl@0
   147
		}
sl@0
   148
	else if	(aCommand.CompareF(KRemoveApps) == 0 )
sl@0
   149
		{
sl@0
   150
		aCmdNum = CertToolDefController::KRemoveAppsCommand;
sl@0
   151
		}
sl@0
   152
	else	
sl@0
   153
		{
sl@0
   154
		return 0;
sl@0
   155
		}
sl@0
   156
sl@0
   157
	return 1;
sl@0
   158
	}
sl@0
   159
	
sl@0
   160
/**
sl@0
   161
 * Returns the mode in which the tool would operate. If the command is invoked 
sl@0
   162
 * with 2 parameters(certool inputFile outputFile), the tool works in non-interactive
sl@0
   163
 * mode else the interactive mode is chosen.
sl@0
   164
 */
sl@0
   165
sl@0
   166
LOCAL_D OperationMode ModeOfOperationL(const CCommandLineArguments& aCmdArgs, RFs& aFs, RFile& aFile)
sl@0
   167
    {
sl@0
   168
    OperationMode mode = Interactive;
sl@0
   169
    if (KeyToolUtils::DoesFileExistsL(aFs,aCmdArgs.Arg(1)))
sl@0
   170
        {
sl@0
   171
		mode = NonInteractive;
sl@0
   172
        TInt error = aFile.Open(aFs, aCmdArgs.Arg(1), EFileRead|EFileShareAny);
sl@0
   173
        aFile.Close();
sl@0
   174
        
sl@0
   175
        TInt error1 = aFile.Replace(aFs, aCmdArgs.Arg(2), EFileWrite|EFileShareExclusive);
sl@0
   176
        // If the input file doesn't exist or not able to create outputfile
sl@0
   177
        // switch to Interactive mode
sl@0
   178
        if (error != KErrNone || error1 != KErrNone)
sl@0
   179
            {
sl@0
   180
            CleanupStack::PopAndDestroy(&aFile);
sl@0
   181
            mode = Interactive;
sl@0
   182
            }   
sl@0
   183
                    
sl@0
   184
         }
sl@0
   185
    return mode;
sl@0
   186
    }
sl@0
   187
sl@0
   188
/**
sl@0
   189
 * The main parsing logic. Same for interactive and non-interactive modes.
sl@0
   190
 */
sl@0
   191
LOCAL_D void ParseAndHandleCommandL(CArrayFixFlat<TPtrC>& aArgs, CCertToolController& aController)
sl@0
   192
    {
sl@0
   193
    CKeyToolParameters* params = CKeyToolParameters::NewLC();
sl@0
   194
            
sl@0
   195
    TInt command = -1; 
sl@0
   196
    TInt i = -1;
sl@0
   197
           
sl@0
   198
    TInt argsCount = aArgs.Count();
sl@0
   199
    while (i < (argsCount-1))
sl@0
   200
        {
sl@0
   201
        i++;
sl@0
   202
        if ((aArgs.At(i).CompareF(KDetails)==0)|| (aArgs.At(i).Compare(KDetailsShort)==0))
sl@0
   203
                    {
sl@0
   204
                    params->iIsDetailed = ETrue;
sl@0
   205
                    continue;
sl@0
   206
                    }
sl@0
   207
        
sl@0
   208
                if (aArgs.At(i).CompareF(KPageWise)==0 || (aArgs.At(i).Compare(KPageWiseShort)==0))
sl@0
   209
                    {
sl@0
   210
                    i++;
sl@0
   211
                    params->iPageWise = ETrue;
sl@0
   212
                    continue;
sl@0
   213
                    }
sl@0
   214
sl@0
   215
                if (aArgs.At(i).Compare(KRemoveKeyAlso)==0)
sl@0
   216
                    {
sl@0
   217
                    params->iRemoveKey = ETrue;
sl@0
   218
                    continue;
sl@0
   219
                    }
sl@0
   220
sl@0
   221
                if (aArgs.At(i).CompareF(KApps)==0)
sl@0
   222
                    {
sl@0
   223
                    i++;
sl@0
   224
                    RArray<TUid> apps;
sl@0
   225
                    TInt k = 0;
sl@0
   226
                    for (k = i; k < argsCount; k++)
sl@0
   227
                        {               
sl@0
   228
                        if (aArgs.At(k).Find(_L("-")) == KErrNotFound)
sl@0
   229
                            {
sl@0
   230
                            TUint uid;
sl@0
   231
                            if (aArgs.At(k).CompareF(KSWInstall)==0)
sl@0
   232
                                {
sl@0
   233
                                uid = swinstalluid;
sl@0
   234
                                }
sl@0
   235
                            else
sl@0
   236
                                {
sl@0
   237
                                if (aArgs.At(k).CompareF(KSWInstallOCSP)==0)
sl@0
   238
                                    {
sl@0
   239
                                    uid = swinstallocspuid;
sl@0
   240
                                    }
sl@0
   241
                                else
sl@0
   242
                                    {
sl@0
   243
                                    if (aArgs.At(k).CompareF(KMidletInstall)==0)
sl@0
   244
                                        {
sl@0
   245
                                        uid = midletinstalluid;
sl@0
   246
                                        }
sl@0
   247
                                    else
sl@0
   248
                                        {
sl@0
   249
                                        if (aArgs.At(k).CompareF(KTls)==0)
sl@0
   250
                                            {
sl@0
   251
                                            uid = tlsuid;
sl@0
   252
                                            }
sl@0
   253
                                        else
sl@0
   254
                                            {
sl@0
   255
                                            // no more valid apps, break cycle
sl@0
   256
                                            break;
sl@0
   257
                                            }
sl@0
   258
                                        }
sl@0
   259
                                    }
sl@0
   260
                                }
sl@0
   261
                            apps.Append(TUid::Uid(uid));                        
sl@0
   262
                            }
sl@0
   263
                        else 
sl@0
   264
                            {
sl@0
   265
                            // We parsed all UIDs, break the cycle and go on!
sl@0
   266
                            break;
sl@0
   267
                            }
sl@0
   268
                        }
sl@0
   269
                    i = k-1;
sl@0
   270
                    params->iUIDs = apps; // We pass on ownership
sl@0
   271
                    params->iIsDetailed = ETrue;
sl@0
   272
                    continue;           
sl@0
   273
                    }
sl@0
   274
            
sl@0
   275
                if (aArgs.At(i).CompareF(KUids)==0)
sl@0
   276
                    {
sl@0
   277
                    i++;
sl@0
   278
                    RArray<TUid> uids;
sl@0
   279
                    TInt k = 0;
sl@0
   280
                    for (k = i; k < argsCount; k++)
sl@0
   281
                        {               
sl@0
   282
                        if (aArgs.At(k).Left(2) == _L("0x"))
sl@0
   283
                            {
sl@0
   284
                            TLex lex(aArgs.At(k).Mid(2));       
sl@0
   285
                            TUint uid =0;
sl@0
   286
                            TInt err = lex.Val(uid, EHex);
sl@0
   287
                            if (err == KErrNone)
sl@0
   288
                                {
sl@0
   289
                                params->iUIDs.Append(TUid::Uid(uid));                       
sl@0
   290
                                }            
sl@0
   291
                            }
sl@0
   292
                        else 
sl@0
   293
                            {
sl@0
   294
                            // We parsed all UIDs, break the cycle and go on!
sl@0
   295
                            break;
sl@0
   296
                            }
sl@0
   297
                        }
sl@0
   298
                    i = k-1;
sl@0
   299
                    params->iIsDetailed = ETrue;
sl@0
   300
                    continue;           
sl@0
   301
                    }
sl@0
   302
                
sl@0
   303
                TDesC& cmd = aArgs.At(i);
sl@0
   304
                if (cmd.CompareF(KLabel) == 0 || 
sl@0
   305
                    cmd.CompareF(KPrivate) == 0 || cmd.CompareF(KStore) == 0 ||
sl@0
   306
                    cmd.CompareF(KOwnerType) == 0 || cmd.Compare(KOwnerTypeShort) == 0 ||
sl@0
   307
                    cmd.CompareF(KHelp) == 0 || cmd.Compare(KHelpShort) == 0 ||
sl@0
   308
                    cmd.CompareF(KDeletable) == 0 || cmd.CompareF(KDeletableShort) == 0)
sl@0
   309
                    {
sl@0
   310
                    i++;
sl@0
   311
                    if (i >= argsCount || aArgs.At(i)[0] == '-')
sl@0
   312
                        {
sl@0
   313
                        i = argsCount;
sl@0
   314
                        command = CertToolDefController::KUsageCommand;
sl@0
   315
                        }
sl@0
   316
                    else if (cmd.CompareF(KHelp) == 0 || cmd.Compare(KHelpShort) == 0)
sl@0
   317
                        {
sl@0
   318
                        params->iDefault = aArgs.At(i).AllocL();
sl@0
   319
                        i = argsCount;  
sl@0
   320
                        }
sl@0
   321
                    else if (cmd.CompareF(KLabel) == 0)
sl@0
   322
                        {
sl@0
   323
                        params->iLabel = aArgs.At(i).AllocL();
sl@0
   324
                        }
sl@0
   325
                    else if (cmd.CompareF(KPrivate) == 0)
sl@0
   326
                        {
sl@0
   327
                        params->iPrivate = aArgs.At(i).AllocL();
sl@0
   328
                        }
sl@0
   329
                    else if (cmd.CompareF(KStore) == 0)
sl@0
   330
                        {
sl@0
   331
                        TLex parser(aArgs.At(i));
sl@0
   332
                        TInt err = parser.Val(params->iCertstoreIndex);
sl@0
   333
                        params->iIsDetailed = ETrue;
sl@0
   334
                        }
sl@0
   335
                    else if (cmd.CompareF(KOwnerType) == 0 || cmd.Compare(KOwnerTypeShort) == 0)
sl@0
   336
                        {
sl@0
   337
                        params->iIsDetailed = ETrue;
sl@0
   338
                        params->iOwnerType = aArgs.At(i).AllocL();
sl@0
   339
                        }
sl@0
   340
                    else if (cmd.CompareF(KDeletable) == 0 || cmd.CompareF(KDeletableShort) == 0)
sl@0
   341
                        {
sl@0
   342
                        params->iIsDetailed = ETrue;
sl@0
   343
                        params->iIsDeletable = aArgs.At(i).AllocL();
sl@0
   344
                        }
sl@0
   345
                    continue;
sl@0
   346
                    }
sl@0
   347
        
sl@0
   348
                if (VerifyCommand(aArgs.At(i), command, i))
sl@0
   349
                    {
sl@0
   350
                    continue;
sl@0
   351
                    }
sl@0
   352
sl@0
   353
                    
sl@0
   354
                if (i!=0) 
sl@0
   355
                    {
sl@0
   356
                    if (aArgs.At(i)[0] == '-')
sl@0
   357
                        {
sl@0
   358
                        i = argsCount;
sl@0
   359
                        command = CertToolDefController::KUsageCommand;
sl@0
   360
                        continue;
sl@0
   361
                        }
sl@0
   362
                    delete params->iDefault;
sl@0
   363
                    params->iDefault = NULL;
sl@0
   364
                    params->iDefault = aArgs.At(i).AllocL();
sl@0
   365
                    params->iIsDetailed = ETrue;            
sl@0
   366
                    }
sl@0
   367
                } 
sl@0
   368
             
sl@0
   369
             
sl@0
   370
            if (command != -1)
sl@0
   371
                {
sl@0
   372
                TRAP_IGNORE(aController.HandleCommandL(command, params));
sl@0
   373
                }
sl@0
   374
            else 
sl@0
   375
                {
sl@0
   376
                aController.HandleCommandL(CertToolDefController::KUsageCommand, params);       
sl@0
   377
                }
sl@0
   378
            CleanupStack::PopAndDestroy(params);
sl@0
   379
            }
sl@0
   380
sl@0
   381
sl@0
   382
/**
sl@0
   383
 * Parsing the command for non-interactive mode.
sl@0
   384
 */
sl@0
   385
sl@0
   386
LOCAL_D void ParseCommandInNonInteractiveModeL(RFile& aFile, const CCommandLineArguments& aCmdArgs)
sl@0
   387
    {
sl@0
   388
  
sl@0
   389
    KeyToolUtils::SetFile(&aFile);
sl@0
   390
    
sl@0
   391
    CKeytoolFileView* view(0); 
sl@0
   392
    view = CKeytoolFileView::NewLC(aCmdArgs.Arg(1));
sl@0
   393
    TInt cmdCount = view->SplitFileInputToArrayL();
sl@0
   394
    
sl@0
   395
    //For every command, parse and handle.
sl@0
   396
    for (TInt j = 0; j < cmdCount; j++)
sl@0
   397
        {
sl@0
   398
        CCertToolController* controller = CCertToolController::NewLC(*view);
sl@0
   399
        
sl@0
   400
        CArrayFixFlat<TPtrC>* args = view->ReadArrayArgumentsLC(j);
sl@0
   401
        ParseAndHandleCommandL(*args, *controller);
sl@0
   402
        
sl@0
   403
        CleanupStack::PopAndDestroy(2, controller);
sl@0
   404
        }
sl@0
   405
        
sl@0
   406
    
sl@0
   407
    CleanupStack::PopAndDestroy(view);
sl@0
   408
    
sl@0
   409
    }
sl@0
   410
sl@0
   411
sl@0
   412
/**
sl@0
   413
 * Parsing the command for interactive mode.
sl@0
   414
 */
sl@0
   415
sl@0
   416
sl@0
   417
LOCAL_D void ParseCommandInInteractiveModeL(CConsoleBase& aConsole, const CCommandLineArguments& aCmdArgs)
sl@0
   418
    {
sl@0
   419
    CArrayFixFlat<TPtrC>* args = new (ELeave) CArrayFixFlat<TPtrC> (10);
sl@0
   420
    CleanupStack::PushL(args);
sl@0
   421
    CKeytoolConsoleView* view = CKeytoolConsoleView::NewLC(aConsole);
sl@0
   422
    CCertToolController* controller = CCertToolController::NewLC(*view);
sl@0
   423
sl@0
   424
    TInt cmdArgsCount = aCmdArgs.Count();
sl@0
   425
    
sl@0
   426
    KeyToolUtils::SetConsole(&aConsole);
sl@0
   427
    BoilerPlateL(&aConsole);
sl@0
   428
    
sl@0
   429
    for (TInt i = 0; i < cmdArgsCount; i++)
sl@0
   430
        {
sl@0
   431
        args->AppendL(aCmdArgs.Arg(i));
sl@0
   432
        }
sl@0
   433
    
sl@0
   434
    //Interactive mode can handle only one command at a time.
sl@0
   435
    ParseAndHandleCommandL(*args, *controller); 
sl@0
   436
    
sl@0
   437
    // We are done!
sl@0
   438
    aConsole.Printf(KNewLine);
sl@0
   439
    aConsole.Printf(KDone);
sl@0
   440
    aConsole.Getch(); 
sl@0
   441
    
sl@0
   442
    CleanupStack::PopAndDestroy(3, args); // controller, view, args
sl@0
   443
    
sl@0
   444
    }
sl@0
   445
sl@0
   446
/**
sl@0
   447
 * Parses the command line and given control to the handler to deal with the request.
sl@0
   448
 */
sl@0
   449
LOCAL_D void DoMainL() 
sl@0
   450
	{
sl@0
   451
sl@0
   452
	RFs fs;
sl@0
   453
	User::LeaveIfError(fs.Connect());
sl@0
   454
	CleanupClosePushL(fs);
sl@0
   455
	RFile file;
sl@0
   456
	
sl@0
   457
	CConsoleBase* console = Console::NewL(KShortName, TSize(KConsFullScreen, KConsFullScreen));
sl@0
   458
	CleanupStack::PushL(console);
sl@0
   459
	CCommandLineArguments* cmdArgs = CCommandLineArguments::NewLC();
sl@0
   460
	TInt cmdArgsCount = cmdArgs->Count();
sl@0
   461
	
sl@0
   462
	
sl@0
   463
	OperationMode currentMode = Interactive; //Interactive by default.
sl@0
   464
	
sl@0
   465
	// Determine the mode of operation as either interactive or non-interactive.
sl@0
   466
	if (cmdArgsCount == 3)
sl@0
   467
		{
sl@0
   468
		currentMode = ModeOfOperationL(*cmdArgs, fs, file);
sl@0
   469
		}
sl@0
   470
		
sl@0
   471
	switch(currentMode)
sl@0
   472
	    {
sl@0
   473
	    case Interactive:
sl@0
   474
	        ParseCommandInInteractiveModeL(*console, *cmdArgs);
sl@0
   475
	        break;
sl@0
   476
	        
sl@0
   477
	    case NonInteractive:
sl@0
   478
	        //file refers to the output file name.
sl@0
   479
	        CleanupClosePushL(file);
sl@0
   480
	        ParseCommandInNonInteractiveModeL(file, *cmdArgs);
sl@0
   481
	        CleanupStack::PopAndDestroy(&file);
sl@0
   482
	        break;
sl@0
   483
	    }
sl@0
   484
sl@0
   485
	CleanupStack::PopAndDestroy(3, &fs);
sl@0
   486
	}
sl@0
   487
sl@0
   488
	
sl@0
   489
sl@0
   490
GLDEF_C TInt E32Main()         // main function called by E32
sl@0
   491
   	{
sl@0
   492
	__UHEAP_MARK;
sl@0
   493
	CTrapCleanup* cleanup=CTrapCleanup::New(); 
sl@0
   494
	
sl@0
   495
	TRAP_IGNORE(DoMainL());
sl@0
   496
	
sl@0
   497
	delete cleanup; 
sl@0
   498
	__UHEAP_MARKEND;
sl@0
   499
	return 0; 
sl@0
   500
   	}
sl@0
   501