1f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)/* 2f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) ********************************************************************** 3f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) * Copyright (C) 2002-2007, International Business Machines 4f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) * Corporation and others. All Rights Reserved. 5f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) ********************************************************************** 6f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) * file name: utfperf.cpp 7f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) * encoding: US-ASCII 8f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) * tab size: 8 (not used) 9f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) * indentation:4 10f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) * 11f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) * created on: 2005Nov17 12f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) * created by: Raymond Yang 13f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) * 14f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) * Ported from utfper.c created by Markus W. Scherer 15f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) * Performance test program for Unicode converters 16f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) */ 17f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) 18f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)#include <stdio.h> 19f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)#include <stdlib.h> 20f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)#include "unicode/uperf.h" 21f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)#include "uoptions.h" 22f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) 23f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)#define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0])) 24f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) 25f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)/* definitions and text buffers */ 26f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) 27f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)#define INPUT_CAPACITY (1024*1024) 28f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)#define INTERMEDIATE_CAPACITY 4096 29f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)#define INTERMEDIATE_SMALL_CAPACITY 20 30f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)#define PIVOT_CAPACITY 1024 31f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)#define OUTPUT_CAPACITY INPUT_CAPACITY 32f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) 33f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)static char utf8[INPUT_CAPACITY]; 34f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)static UChar pivot[INTERMEDIATE_CAPACITY]; 35f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) 36f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)static UChar output[OUTPUT_CAPACITY]; 37f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)static char intermediate[OUTPUT_CAPACITY]; 38f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) 39f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)static int32_t utf8Length, encodedLength, outputLength, countInputCodePoints; 40f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) 41f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)static int32_t fromUCallbackCount; 42f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) 43f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)// Command-line options specific to utfperf. 44f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)// Options do not have abbreviations: Force readable command lines. 45f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)// (Using U+0001 for abbreviation characters.) 46f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)enum { 47f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) CHARSET, 48f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) CHUNK_LENGTH, 49f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) PIVOT_LENGTH, 50f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) UTFPERF_OPTIONS_COUNT 51f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)}; 52f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) 53f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)static UOption options[UTFPERF_OPTIONS_COUNT]={ 54f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) UOPTION_DEF("charset", '\x01', UOPT_REQUIRES_ARG), 55f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) UOPTION_DEF("chunk", '\x01', UOPT_REQUIRES_ARG), 56f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) UOPTION_DEF("pivot", '\x01', UOPT_REQUIRES_ARG) 57f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)}; 58f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) 59f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)static const char *const utfperf_usage = 60f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) "\t--charset Charset for which to test performance, e.g. windows-1251.\n" 61f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) "\t Default: UTF-8\n" 62f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) "\t--chunk Length (in bytes) of charset output chunks. [4096]\n" 63f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) "\t--pivot Length (in UChars) of the UTF-16 pivot buffer, if applicable.\n" 64f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) "\t [1024]\n"; 65f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) 66f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)// Test object. 67f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)class UtfPerformanceTest : public UPerfTest{ 68f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)public: 69f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) UtfPerformanceTest(int32_t argc, const char *argv[], UErrorCode &status) 70f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) : UPerfTest(argc, argv, options, LENGTHOF(options), utfperf_usage, status) { 71f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) if (U_SUCCESS(status)) { 72f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) charset = options[CHARSET].value; 73f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) 74f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) chunkLength = atoi(options[CHUNK_LENGTH].value); 75f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) if (chunkLength < 1 || OUTPUT_CAPACITY < chunkLength) { 76f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) fprintf(stderr, "error: chunk length must be 1..%ld\n", (long)OUTPUT_CAPACITY); 77f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) status = U_ILLEGAL_ARGUMENT_ERROR; 78f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) } 79f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) 80f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) pivotLength = atoi(options[PIVOT_LENGTH].value); 81f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) if (pivotLength < 1 || PIVOT_CAPACITY < pivotLength) { 82f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) fprintf(stderr, "error: pivot length must be 1..%ld\n", (long)PIVOT_CAPACITY); 83f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) status = U_ILLEGAL_ARGUMENT_ERROR; 84f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) } 85f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) 86f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) int32_t inputLength; 87f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) UPerfTest::getBuffer(inputLength, status); 88f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) countInputCodePoints = u_countChar32(buffer, bufferLen); 89f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) u_strToUTF8(utf8, (int32_t)sizeof(utf8), &utf8Length, buffer, bufferLen, &status); 90f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) } 91f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) } 92f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) 93f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) virtual UPerfFunction* runIndexedTest(int32_t index, UBool exec, const char* &name, char* par = NULL); 94f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) 95f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) const UChar *getBuffer() const { return buffer; } 96f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) int32_t getBufferLen() const { return bufferLen; } 97f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) 98f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) const char *charset; 99f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) int32_t chunkLength, pivotLength; 100f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)}; 101f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) 102f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)U_CDECL_BEGIN 103f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)// Custom callback for counting callback calls. 104f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)static void U_CALLCONV 105f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)fromUCallback(const void *context, 106f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) UConverterFromUnicodeArgs *fromUArgs, 107f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) const UChar *codeUnits, 108f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) int32_t length, 109f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) UChar32 codePoint, 110f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) UConverterCallbackReason reason, 111f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) UErrorCode *pErrorCode) { 112f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) if (reason <= UCNV_IRREGULAR) { 113f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) ++fromUCallbackCount; 114f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) } 115f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) UCNV_FROM_U_CALLBACK_SUBSTITUTE(context, fromUArgs, codeUnits, length, codePoint, reason, pErrorCode); 116f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)} 117f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)U_CDECL_END 118f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) 119f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)// Base class for Roundtrip, FromUnicode and FromUTF8 with common setup. 120f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)class Command : public UPerfFunction { 121f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)protected: 122f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) Command(const UtfPerformanceTest &testcase) 123f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) : testcase(testcase), 124f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) input(testcase.getBuffer()), inputLength(testcase.getBufferLen()), 125f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) errorCode(U_ZERO_ERROR) { 126f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) cnv=ucnv_open(testcase.charset, &errorCode); 127f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) if (U_FAILURE(errorCode)) { 128f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) fprintf(stderr, "error opening converter for \"%s\" - %s\n", testcase.charset, u_errorName(errorCode)); 129f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) } 130f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) ucnv_setFromUCallBack(cnv, fromUCallback, NULL, NULL, NULL, &errorCode); 131f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) } 132f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)public: 133f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) virtual ~Command(){ 134f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) if(U_SUCCESS(errorCode)) { 135f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) ucnv_close(cnv); 136f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) } 137f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) } 138f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) // virtual void call(UErrorCode* pErrorCode) { ... } 139f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) virtual long getOperationsPerIteration(){ 140f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) return countInputCodePoints; 141f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) } 142f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) 143f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) const UtfPerformanceTest &testcase; 144f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) const UChar *input; 145f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) int32_t inputLength; 146f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) UErrorCode errorCode; 147f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) UConverter *cnv; 148f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)}; 149f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) 150f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)// Test roundtrip UTF-16->encoding->UTF-16. 151f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)class Roundtrip : public Command { 152f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)protected: 153f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) Roundtrip(const UtfPerformanceTest &testcase) : Command(testcase) {} 154f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)public: 155f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) static UPerfFunction* get(const UtfPerformanceTest &testcase) { 156f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) Roundtrip * t = new Roundtrip(testcase); 157f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) if (U_SUCCESS(t->errorCode)){ 158f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) return t; 159f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) } else { 160f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) delete t; 161f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) return NULL; 162f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) } 163f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) } 164f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) virtual void call(UErrorCode* pErrorCode){ 165f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) const UChar *pIn, *pInLimit; 166f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) UChar *pOut, *pOutLimit; 167f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) char *pInter, *pInterLimit; 168f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) const char *p; 169f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) UBool flush; 170f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) 171f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) ucnv_reset(cnv); 172f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) fromUCallbackCount=0; 173f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) 174f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) pIn=input; 175f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) pInLimit=input+inputLength; 176f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) 177f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) pOut=output; 178f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) pOutLimit=output+OUTPUT_CAPACITY; 179f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) 180f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) pInterLimit=intermediate+testcase.chunkLength; 181f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) 182f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) encodedLength=outputLength=0; 183f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) flush=FALSE; 184f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) 185f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) do { 186f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) /* convert a block of [pIn..pInLimit[ to the encoding in intermediate[] */ 187f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) pInter=intermediate; 188f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) ucnv_fromUnicode(cnv, &pInter, pInterLimit, &pIn, pInLimit, NULL, TRUE, pErrorCode); 189f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) encodedLength+=(int32_t)(pInter-intermediate); 190f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) 191f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) if(*pErrorCode==U_BUFFER_OVERFLOW_ERROR) { 192f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) /* make sure that we convert once more to really flush */ 193f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) *pErrorCode=U_ZERO_ERROR; 194f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) } else if(U_FAILURE(*pErrorCode)) { 195f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) return; 196f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) } else if(pIn==pInLimit) { 197f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) flush=TRUE; 198f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) } 199f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) 200f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) /* convert the block [intermediate..pInter[ back to UTF-16 */ 201f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) p=intermediate; 202f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) ucnv_toUnicode(cnv, &pOut, pOutLimit,&p, pInter,NULL, flush,pErrorCode); 203f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) if(U_FAILURE(*pErrorCode)) { 204f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) return; 205f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) } 206f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) /* intermediate must have been consumed (p==pInter) because of the converter semantics */ 207f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) } while(!flush); 208f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) 209f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) outputLength=pOut-output; 210f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) if(inputLength!=outputLength) { 211f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) fprintf(stderr, "error: roundtrip failed, inputLength %d!=outputLength %d\n", inputLength, outputLength); 212f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) *pErrorCode=U_INTERNAL_PROGRAM_ERROR; 213f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) } 214f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) } 215f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)}; 216f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) 217f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)// Test one-way conversion UTF-16->encoding. 218f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)class FromUnicode : public Command { 219f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)protected: 220f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) FromUnicode(const UtfPerformanceTest &testcase) : Command(testcase) {} 221f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)public: 222f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) static UPerfFunction* get(const UtfPerformanceTest &testcase) { 223f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) FromUnicode * t = new FromUnicode(testcase); 224f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) if (U_SUCCESS(t->errorCode)){ 225f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) return t; 226f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) } else { 227f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) delete t; 228f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) return NULL; 229f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) } 230f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) } 231f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) virtual void call(UErrorCode* pErrorCode){ 232f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) const UChar *pIn, *pInLimit; 233f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) char *pInter, *pInterLimit; 234f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) 235f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) ucnv_resetFromUnicode(cnv); 236f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) fromUCallbackCount=0; 237f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) 238f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) pIn=input; 239f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) pInLimit=input+inputLength; 240f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) 241f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) pInterLimit=intermediate+testcase.chunkLength; 242f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) 243f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) encodedLength=0; 244f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) 245f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) for(;;) { 246f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) pInter=intermediate; 247f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) ucnv_fromUnicode(cnv, &pInter, pInterLimit, &pIn, pInLimit, NULL, TRUE, pErrorCode); 248f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) encodedLength+=(int32_t)(pInter-intermediate); 249f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) 250f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) if(*pErrorCode==U_BUFFER_OVERFLOW_ERROR) { 251f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) /* make sure that we convert once more to really flush */ 252f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) *pErrorCode=U_ZERO_ERROR; 253f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) } else if(U_FAILURE(*pErrorCode)) { 254f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) return; 255f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) } else { 256f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) break; // all done 257f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) } 258f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) } 259f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) } 260f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)}; 261f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) 262f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)// Test one-way conversion UTF-8->encoding. 263f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)class FromUTF8 : public Command { 264f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)protected: 265f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) FromUTF8(const UtfPerformanceTest &testcase) 266f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) : Command(testcase), 267f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) utf8Cnv(NULL), 268f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) input8(utf8), input8Length(utf8Length) { 269f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) utf8Cnv=ucnv_open("UTF-8", &errorCode); 270f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) } 271f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)public: 272f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) static UPerfFunction* get(const UtfPerformanceTest &testcase) { 273f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) FromUTF8 * t = new FromUTF8(testcase); 274f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) if (U_SUCCESS(t->errorCode)){ 275f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) return t; 276f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) } else { 277f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) delete t; 278f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) return NULL; 279f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) } 280f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) } 281f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) ~FromUTF8() { 282f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) ucnv_close(utf8Cnv); 283f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) } 284f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) virtual void call(UErrorCode* pErrorCode){ 285f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) const char *pIn, *pInLimit; 286f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) char *pInter, *pInterLimit; 287f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) UChar *pivotSource, *pivotTarget, *pivotLimit; 288f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) 289f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) ucnv_resetToUnicode(utf8Cnv); 290f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) ucnv_resetFromUnicode(cnv); 291f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) fromUCallbackCount=0; 292f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) 293f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) pIn=input8; 294f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) pInLimit=input8+input8Length; 295f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) 296f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) pInterLimit=intermediate+testcase.chunkLength; 297f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) 298f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) pivotSource=pivotTarget=pivot; 299f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) pivotLimit=pivot+testcase.pivotLength; 300f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) 301f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) encodedLength=0; 302f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) 303f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) for(;;) { 304f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) pInter=intermediate; 305f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) ucnv_convertEx(cnv, utf8Cnv, 306f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) &pInter, pInterLimit, 307f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) &pIn, pInLimit, 308f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) pivot, &pivotSource, &pivotTarget, pivotLimit, 309f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) FALSE, TRUE, pErrorCode); 310f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) encodedLength+=(int32_t)(pInter-intermediate); 311f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) 312f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) if(*pErrorCode==U_BUFFER_OVERFLOW_ERROR) { 313f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) /* make sure that we convert once more to really flush */ 314f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) *pErrorCode=U_ZERO_ERROR; 315f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) } else if(U_FAILURE(*pErrorCode)) { 316f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) return; 317f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) } else { 318f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) break; // all done 319f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) } 320f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) } 321f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) } 322f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)protected: 323f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) UConverter *utf8Cnv; 324f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) const char *input8; 325f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) int32_t input8Length; 326f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)}; 327f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) 328f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)UPerfFunction* UtfPerformanceTest::runIndexedTest(int32_t index, UBool exec, const char* &name, char* par) { 329f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) switch (index) { 330f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) case 0: name = "Roundtrip"; if (exec) return Roundtrip::get(*this); break; 331f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) case 1: name = "FromUnicode"; if (exec) return FromUnicode::get(*this); break; 332f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) case 2: name = "FromUTF8"; if (exec) return FromUTF8::get(*this); break; 333f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) default: name = ""; break; 334f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) } 335f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) return NULL; 336f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)} 337f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) 338f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)int main(int argc, const char *argv[]) 339f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles){ 340f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) // Default values for command-line options. 341f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) options[CHARSET].value = "UTF-8"; 342f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) options[CHUNK_LENGTH].value = "4096"; 343f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) options[PIVOT_LENGTH].value = "1024"; 344f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) 345f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) UErrorCode status = U_ZERO_ERROR; 346f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) UtfPerformanceTest test(argc, argv, status); 347f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) 348f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) if (U_FAILURE(status)){ 349f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) printf("The error is %s\n", u_errorName(status)); 350f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) test.usage(); 351f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) return status; 352f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) } 353f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) 354f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) if (test.run() == FALSE){ 355f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) fprintf(stderr, "FAILED: Tests could not be run please check the " 356f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) "arguments.\n"); 357f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) return -1; 358f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) } 359f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) 360f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) if (fromUCallbackCount > 0) { 361f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) printf("Number of fromUnicode callback calls in the last iteration: %ld\n", (long)fromUCallbackCount); 362f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) } 363f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) 364f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles) return 0; 365f4ed1cf5d184064c4cf0e4359c6d5d8aadb50afaTorne (Richard Coles)} 366