19949213aSStephan Aßmus //////////////////////////////////////////////////////////////////////////////// 29949213aSStephan Aßmus // 39949213aSStephan Aßmus // File: GIFTranslator.cpp 49949213aSStephan Aßmus // 59949213aSStephan Aßmus // Date: December 1999 69949213aSStephan Aßmus // 79949213aSStephan Aßmus // Author: Daniel Switkin 89949213aSStephan Aßmus // 99949213aSStephan Aßmus // Copyright 2003 (c) by Daniel Switkin. This file is made publically available 109949213aSStephan Aßmus // under the BSD license, with the stipulations that this complete header must 119949213aSStephan Aßmus // remain at the top of the file indefinitely, and credit must be given to the 129949213aSStephan Aßmus // original author in any about box using this software. 139949213aSStephan Aßmus // 149949213aSStephan Aßmus //////////////////////////////////////////////////////////////////////////////// 155e4c29a6SJohn Scipione 16abfe23dcSPhilippe Saint-Pierre // Additional authors: Stephan Aßmus, <superstippi@gmx.de> 175e4c29a6SJohn Scipione // John Scipione, <jscipione@gmail.com> 189949213aSStephan Aßmus 199949213aSStephan Aßmus #include "GIFTranslator.h" 205e4c29a6SJohn Scipione 215e4c29a6SJohn Scipione #include <stdio.h> 225e4c29a6SJohn Scipione #include <stdlib.h> 235e4c29a6SJohn Scipione #include <string.h> 245e4c29a6SJohn Scipione #include <syslog.h> 2570d59669SSiarzhuk Zharski 26abfe23dcSPhilippe Saint-Pierre #include <Application.h> 279949213aSStephan Aßmus #include <ByteOrder.h> 2870d59669SSiarzhuk Zharski #include <Catalog.h> 299949213aSStephan Aßmus #include <DataIO.h> 3070d59669SSiarzhuk Zharski #include <InterfaceDefs.h> 319949213aSStephan Aßmus #include <TranslatorAddOn.h> 329949213aSStephan Aßmus #include <TranslatorFormats.h> 33c030befbSJohn Scipione #include <TypeConstants.h> 3470d59669SSiarzhuk Zharski 355e4c29a6SJohn Scipione #include "GIFLoad.h" 36c030befbSJohn Scipione #include "GIFSave.h" 37c030befbSJohn Scipione #include "GIFView.h" 38abfe23dcSPhilippe Saint-Pierre #include "TranslatorWindow.h" 39abfe23dcSPhilippe Saint-Pierre 405e4c29a6SJohn Scipione 419949213aSStephan Aßmus #ifndef GIF_TYPE 429949213aSStephan Aßmus #define GIF_TYPE 'GIF ' 439949213aSStephan Aßmus #endif 449949213aSStephan Aßmus 45546208a5SOliver Tappe #undef B_TRANSLATION_CONTEXT 46546208a5SOliver Tappe #define B_TRANSLATION_CONTEXT "GIFTranslator" 4770d59669SSiarzhuk Zharski 4870d59669SSiarzhuk Zharski 499949213aSStephan Aßmus bool debug = false; 505e4c29a6SJohn Scipione // this global will be externed in other files - set once here 515e4c29a6SJohn Scipione // for the entire translator 529949213aSStephan Aßmus 535e4c29a6SJohn Scipione bool DetermineType(BPositionIO* source, bool* isGif); 549949213aSStephan Aßmus status_t GetBitmap(BPositionIO* in, BBitmap** out); 559949213aSStephan Aßmus 56abfe23dcSPhilippe Saint-Pierre static const translation_format sInputFormats[] = { 575e4c29a6SJohn Scipione { 585e4c29a6SJohn Scipione GIF_TYPE, 595e4c29a6SJohn Scipione B_TRANSLATOR_BITMAP, 605e4c29a6SJohn Scipione GIF_IN_QUALITY, 615e4c29a6SJohn Scipione GIF_IN_CAPABILITY, 625e4c29a6SJohn Scipione "image/gif", 635e4c29a6SJohn Scipione "GIF image" 645e4c29a6SJohn Scipione }, 655e4c29a6SJohn Scipione { 665e4c29a6SJohn Scipione B_TRANSLATOR_BITMAP, 675e4c29a6SJohn Scipione B_TRANSLATOR_BITMAP, 685e4c29a6SJohn Scipione BBM_IN_QUALITY, 695e4c29a6SJohn Scipione BBM_IN_CAPABILITY, 705e4c29a6SJohn Scipione "image/x-be-bitmap", 715e4c29a6SJohn Scipione "Be Bitmap Format (GIFTranslator)" 725e4c29a6SJohn Scipione } 739949213aSStephan Aßmus }; 749949213aSStephan Aßmus 75abfe23dcSPhilippe Saint-Pierre static const translation_format sOutputFormats[] = { 765e4c29a6SJohn Scipione { 775e4c29a6SJohn Scipione GIF_TYPE, 785e4c29a6SJohn Scipione B_TRANSLATOR_BITMAP, 795e4c29a6SJohn Scipione GIF_OUT_QUALITY, 805e4c29a6SJohn Scipione GIF_OUT_CAPABILITY, 815e4c29a6SJohn Scipione "image/gif", 825e4c29a6SJohn Scipione "GIF image" 835e4c29a6SJohn Scipione }, 845e4c29a6SJohn Scipione { 855e4c29a6SJohn Scipione B_TRANSLATOR_BITMAP, 865e4c29a6SJohn Scipione B_TRANSLATOR_BITMAP, 875e4c29a6SJohn Scipione BBM_OUT_QUALITY, 885e4c29a6SJohn Scipione BBM_OUT_CAPABILITY, 895e4c29a6SJohn Scipione "image/x-be-bitmap", 905e4c29a6SJohn Scipione "Be Bitmap Format (GIFTranslator)" 915e4c29a6SJohn Scipione } 929949213aSStephan Aßmus }; 939949213aSStephan Aßmus 94abfe23dcSPhilippe Saint-Pierre // Default settings for the Translator 95abfe23dcSPhilippe Saint-Pierre static const TranSetting sDefaultSettings[] = { 96abfe23dcSPhilippe Saint-Pierre { B_TRANSLATOR_EXT_HEADER_ONLY, TRAN_SETTING_BOOL, false }, 97abfe23dcSPhilippe Saint-Pierre { B_TRANSLATOR_EXT_DATA_ONLY, TRAN_SETTING_BOOL, false }, 98abfe23dcSPhilippe Saint-Pierre { GIF_SETTING_INTERLACED, TRAN_SETTING_BOOL, false }, 99*5fa8801fSJohn Scipione { GIF_SETTING_USE_TRANSPARENT, TRAN_SETTING_BOOL, true }, 100*5fa8801fSJohn Scipione { GIF_SETTING_USE_TRANSPARENT_AUTO, TRAN_SETTING_BOOL, true }, 101abfe23dcSPhilippe Saint-Pierre { GIF_SETTING_USE_DITHERING, TRAN_SETTING_BOOL, false }, 102*5fa8801fSJohn Scipione { GIF_SETTING_PALETTE_MODE, TRAN_SETTING_INT32, 3 }, 103abfe23dcSPhilippe Saint-Pierre { GIF_SETTING_PALETTE_SIZE, TRAN_SETTING_INT32, 8 }, 104*5fa8801fSJohn Scipione { GIF_SETTING_TRANSPARENT_RED, TRAN_SETTING_INT32, 255 }, 105*5fa8801fSJohn Scipione { GIF_SETTING_TRANSPARENT_GREEN, TRAN_SETTING_INT32, 255 }, 106*5fa8801fSJohn Scipione { GIF_SETTING_TRANSPARENT_BLUE, TRAN_SETTING_INT32, 255 } 107abfe23dcSPhilippe Saint-Pierre }; 1089949213aSStephan Aßmus 1092d612ef7SJohn Scipione const uint32 kNumInputFormats = sizeof(sInputFormats) 1102d612ef7SJohn Scipione / sizeof(translation_format); 1112d612ef7SJohn Scipione const uint32 kNumOutputFormats = sizeof(sOutputFormats) 1122d612ef7SJohn Scipione / sizeof(translation_format); 1132d612ef7SJohn Scipione const uint32 kNumDefaultSettings = sizeof(sDefaultSettings) 1142d612ef7SJohn Scipione / sizeof(TranSetting); 1159949213aSStephan Aßmus 1169949213aSStephan Aßmus 1175adf9d6eSJohn Scipione /*! Look at first few bytes in stream to determine type - throw it back 1185adf9d6eSJohn Scipione if it is not a GIF or a BBitmap that we understand. 1195e4c29a6SJohn Scipione */ 1209949213aSStephan Aßmus bool 1215e4c29a6SJohn Scipione DetermineType(BPositionIO* source, bool* isGif) 1229949213aSStephan Aßmus { 1239949213aSStephan Aßmus unsigned char header[7]; 1245e4c29a6SJohn Scipione *isGif = true; 125abfe23dcSPhilippe Saint-Pierre if (source->Read(header, 6) != 6) 126abfe23dcSPhilippe Saint-Pierre return false; 12701be25aeSJohn Scipione 1289949213aSStephan Aßmus header[6] = 0x00; 1299949213aSStephan Aßmus 1305e4c29a6SJohn Scipione if (strcmp((char*)header, "GIF87a") != 0 1315e4c29a6SJohn Scipione && strcmp((char*)header, "GIF89a") != 0) { 1325e4c29a6SJohn Scipione *isGif = false; 13370d59669SSiarzhuk Zharski int32 magic = (header[0] << 24) + (header[1] << 16) + (header[2] << 8) 13470d59669SSiarzhuk Zharski + header[3]; 135abfe23dcSPhilippe Saint-Pierre if (magic != B_TRANSLATOR_BITMAP) 136abfe23dcSPhilippe Saint-Pierre return false; 1375e4c29a6SJohn Scipione 1389949213aSStephan Aßmus source->Seek(5 * 4 - 2, SEEK_CUR); 1399949213aSStephan Aßmus color_space cs; 140abfe23dcSPhilippe Saint-Pierre if (source->Read(&cs, 4) != 4) 141abfe23dcSPhilippe Saint-Pierre return false; 1425e4c29a6SJohn Scipione 1439949213aSStephan Aßmus cs = (color_space)B_BENDIAN_TO_HOST_INT32(cs); 144abfe23dcSPhilippe Saint-Pierre if (cs != B_RGB32 && cs != B_RGBA32 && cs != B_RGB32_BIG 1455e4c29a6SJohn Scipione && cs != B_RGBA32_BIG) { 146abfe23dcSPhilippe Saint-Pierre return false; 1479949213aSStephan Aßmus } 1485e4c29a6SJohn Scipione } 1499949213aSStephan Aßmus 1509949213aSStephan Aßmus source->Seek(0, SEEK_SET); 1519949213aSStephan Aßmus return true; 1529949213aSStephan Aßmus } 1539949213aSStephan Aßmus 1549949213aSStephan Aßmus 1559949213aSStephan Aßmus status_t 1569949213aSStephan Aßmus GetBitmap(BPositionIO* in, BBitmap** out) 1579949213aSStephan Aßmus { 1589949213aSStephan Aßmus TranslatorBitmap header; 15901be25aeSJohn Scipione status_t result = in->Read(&header, sizeof(header)); 16001be25aeSJohn Scipione if (result != sizeof(header)) 1619949213aSStephan Aßmus return B_IO_ERROR; 1629949213aSStephan Aßmus 1639949213aSStephan Aßmus header.magic = B_BENDIAN_TO_HOST_INT32(header.magic); 1649949213aSStephan Aßmus header.bounds.left = B_BENDIAN_TO_HOST_FLOAT(header.bounds.left); 1659949213aSStephan Aßmus header.bounds.top = B_BENDIAN_TO_HOST_FLOAT(header.bounds.top); 1669949213aSStephan Aßmus header.bounds.right = B_BENDIAN_TO_HOST_FLOAT(header.bounds.right); 1679949213aSStephan Aßmus header.bounds.bottom = B_BENDIAN_TO_HOST_FLOAT(header.bounds.bottom); 1689949213aSStephan Aßmus header.rowBytes = B_BENDIAN_TO_HOST_INT32(header.rowBytes); 1699949213aSStephan Aßmus header.colors = (color_space)B_BENDIAN_TO_HOST_INT32(header.colors); 1709949213aSStephan Aßmus header.dataSize = B_BENDIAN_TO_HOST_INT32(header.dataSize); 1719949213aSStephan Aßmus 1725e4c29a6SJohn Scipione // dump data from stream into a BBitmap 1737b461148SJohn Scipione *out = new(std::nothrow) BBitmap(header.bounds, header.colors); 1747b461148SJohn Scipione if (*out == NULL) 1757b461148SJohn Scipione return B_NO_MEMORY; 1767b461148SJohn Scipione 17701be25aeSJohn Scipione if (!(*out)->IsValid()) { 17801be25aeSJohn Scipione delete *out; 1799949213aSStephan Aßmus return B_NO_MEMORY; 1809949213aSStephan Aßmus } 1815e4c29a6SJohn Scipione 18201be25aeSJohn Scipione result = in->Read((*out)->Bits(), header.dataSize); 18301be25aeSJohn Scipione if (result != (status_t)header.dataSize) { 18401be25aeSJohn Scipione delete *out; 185de6ba1a0SAdrien Destugues return B_IO_ERROR; 186de6ba1a0SAdrien Destugues } 18701be25aeSJohn Scipione 18801be25aeSJohn Scipione return B_OK; 1899949213aSStephan Aßmus } 1909949213aSStephan Aßmus 1919949213aSStephan Aßmus 1925adf9d6eSJohn Scipione /*! Required identify function - may need to read entire header, not sure 19381abd9edSJohn Scipione */ 1949949213aSStephan Aßmus status_t 195abfe23dcSPhilippe Saint-Pierre GIFTranslator::DerivedIdentify(BPositionIO* inSource, 196abfe23dcSPhilippe Saint-Pierre const translation_format* inFormat, BMessage* ioExtension, 197abfe23dcSPhilippe Saint-Pierre translator_info* outInfo, uint32 outType) 1989949213aSStephan Aßmus { 1999949213aSStephan Aßmus const char* debug_text = getenv("GIF_TRANSLATOR_DEBUG"); 200abfe23dcSPhilippe Saint-Pierre if (debug_text != NULL && atoi(debug_text) != 0) 201abfe23dcSPhilippe Saint-Pierre debug = true; 2029949213aSStephan Aßmus 203abfe23dcSPhilippe Saint-Pierre if (outType == 0) 204abfe23dcSPhilippe Saint-Pierre outType = B_TRANSLATOR_BITMAP; 2055e4c29a6SJohn Scipione 20670d59669SSiarzhuk Zharski if (outType != GIF_TYPE && outType != B_TRANSLATOR_BITMAP) 20770d59669SSiarzhuk Zharski return B_NO_TRANSLATOR; 2089949213aSStephan Aßmus 2095e4c29a6SJohn Scipione bool isGif; 2105e4c29a6SJohn Scipione if (!DetermineType(inSource, &isGif)) 211abfe23dcSPhilippe Saint-Pierre return B_NO_TRANSLATOR; 2125e4c29a6SJohn Scipione 2135e4c29a6SJohn Scipione if (!isGif && inFormat != NULL && inFormat->type != B_TRANSLATOR_BITMAP) 2149949213aSStephan Aßmus return B_NO_TRANSLATOR; 2159949213aSStephan Aßmus 2169949213aSStephan Aßmus outInfo->group = B_TRANSLATOR_BITMAP; 2175e4c29a6SJohn Scipione if (isGif) { 2189949213aSStephan Aßmus outInfo->type = GIF_TYPE; 219abfe23dcSPhilippe Saint-Pierre outInfo->quality = GIF_IN_QUALITY; 220abfe23dcSPhilippe Saint-Pierre outInfo->capability = GIF_IN_CAPABILITY; 221aec33db1SPhilippe Saint-Pierre strlcpy(outInfo->name, B_TRANSLATE("GIF image"), sizeof(outInfo->name)); 2229949213aSStephan Aßmus strcpy(outInfo->MIME, "image/gif"); 223abfe23dcSPhilippe Saint-Pierre } else { 2249949213aSStephan Aßmus outInfo->type = B_TRANSLATOR_BITMAP; 225abfe23dcSPhilippe Saint-Pierre outInfo->quality = BBM_IN_QUALITY; 226abfe23dcSPhilippe Saint-Pierre outInfo->capability = BBM_IN_CAPABILITY; 227aec33db1SPhilippe Saint-Pierre strlcpy(outInfo->name, B_TRANSLATE("Be Bitmap Format (GIFTranslator)"), 2283927bd3cSPhilippe Saint-Pierre sizeof(outInfo->name)); 2299949213aSStephan Aßmus strcpy(outInfo->MIME, "image/x-be-bitmap"); 2309949213aSStephan Aßmus } 2315e4c29a6SJohn Scipione 2329949213aSStephan Aßmus return B_OK; 2339949213aSStephan Aßmus } 2349949213aSStephan Aßmus 2359949213aSStephan Aßmus 2365adf9d6eSJohn Scipione /*! Main required function - assumes that an incoming GIF must be translated 2375adf9d6eSJohn Scipione to a BBitmap, and vice versa - this could be improved 2385e4c29a6SJohn Scipione */ 2399949213aSStephan Aßmus status_t 240abfe23dcSPhilippe Saint-Pierre GIFTranslator::DerivedTranslate(BPositionIO* inSource, 241abfe23dcSPhilippe Saint-Pierre const translator_info* inInfo, BMessage* ioExtension, uint32 outType, 242abfe23dcSPhilippe Saint-Pierre BPositionIO* outDestination, int32 baseType) 2439949213aSStephan Aßmus { 2449949213aSStephan Aßmus const char* debug_text = getenv("GIF_TRANSLATOR_DEBUG"); 2455e4c29a6SJohn Scipione if (debug_text != NULL && atoi(debug_text) != 0) 2465e4c29a6SJohn Scipione debug = true; 2479949213aSStephan Aßmus 2485e4c29a6SJohn Scipione if (outType == 0) 2495e4c29a6SJohn Scipione outType = B_TRANSLATOR_BITMAP; 2505e4c29a6SJohn Scipione 2515e4c29a6SJohn Scipione if (outType != GIF_TYPE && outType != B_TRANSLATOR_BITMAP) 2529949213aSStephan Aßmus return B_NO_TRANSLATOR; 2539949213aSStephan Aßmus 2545e4c29a6SJohn Scipione bool isGif; 2555e4c29a6SJohn Scipione if (!DetermineType(inSource, &isGif)) 2565e4c29a6SJohn Scipione return B_NO_TRANSLATOR; 2575e4c29a6SJohn Scipione 2585e4c29a6SJohn Scipione if (!isGif && inInfo->type != B_TRANSLATOR_BITMAP) 2595e4c29a6SJohn Scipione return B_NO_TRANSLATOR; 2609949213aSStephan Aßmus 26101be25aeSJohn Scipione status_t result = B_OK; 2629949213aSStephan Aßmus bigtime_t now = system_time(); 2635e4c29a6SJohn Scipione 2645e4c29a6SJohn Scipione if (!isGif) { 2655e4c29a6SJohn Scipione // BBitmap to GIF 266116e78d4SJohn Scipione BBitmap* bitmap; 26701be25aeSJohn Scipione result = GetBitmap(inSource, &bitmap); 26801be25aeSJohn Scipione if (result != B_OK) 26901be25aeSJohn Scipione return result; 2705e4c29a6SJohn Scipione 27178bfaa98SJohn Scipione GIFSave* gifSave = new(std::nothrow) GIFSave(bitmap, outDestination, 27278bfaa98SJohn Scipione fSettings); 27378bfaa98SJohn Scipione if (gifSave == NULL) { 27478bfaa98SJohn Scipione delete bitmap; 27578bfaa98SJohn Scipione return B_NO_MEMORY; 27678bfaa98SJohn Scipione } 27778bfaa98SJohn Scipione 27881abd9edSJohn Scipione if (gifSave->fatalerror) { 27981abd9edSJohn Scipione delete gifSave; 2807bc02c61SStefano Ceccherini delete bitmap; 2819949213aSStephan Aßmus return B_NO_MEMORY; 2829949213aSStephan Aßmus } 28381abd9edSJohn Scipione delete gifSave; 2847bc02c61SStefano Ceccherini delete bitmap; 2855e4c29a6SJohn Scipione } else { 2865e4c29a6SJohn Scipione // GIF to BBitmap 28778bfaa98SJohn Scipione GIFLoad* gifLoad = new(std::nothrow) GIFLoad(inSource, outDestination); 28878bfaa98SJohn Scipione if (gifLoad == NULL) 28978bfaa98SJohn Scipione return B_NO_MEMORY; 29078bfaa98SJohn Scipione 2915e4c29a6SJohn Scipione if (gifLoad->fatalerror) { 2925e4c29a6SJohn Scipione delete gifLoad; 2939949213aSStephan Aßmus return B_NO_MEMORY; 2949949213aSStephan Aßmus } 2955e4c29a6SJohn Scipione delete gifLoad; 2969949213aSStephan Aßmus } 2979949213aSStephan Aßmus 2989949213aSStephan Aßmus if (debug) { 2999949213aSStephan Aßmus now = system_time() - now; 30084bff752SJohn Scipione syslog(LOG_INFO, "Translate() - Translation took %Ld microseconds\n", 3015e4c29a6SJohn Scipione now); 3029949213aSStephan Aßmus } 3039949213aSStephan Aßmus return B_OK; 3049949213aSStephan Aßmus } 3059949213aSStephan Aßmus 3069949213aSStephan Aßmus 307abfe23dcSPhilippe Saint-Pierre BTranslator* 308abfe23dcSPhilippe Saint-Pierre make_nth_translator(int32 n, image_id you, uint32 flags, ...) 3099949213aSStephan Aßmus { 310abfe23dcSPhilippe Saint-Pierre if (n == 0) 31178bfaa98SJohn Scipione return new(std::nothrow) GIFTranslator(); 312abfe23dcSPhilippe Saint-Pierre 313abfe23dcSPhilippe Saint-Pierre return NULL; 314abfe23dcSPhilippe Saint-Pierre } 315abfe23dcSPhilippe Saint-Pierre 316abfe23dcSPhilippe Saint-Pierre 317abfe23dcSPhilippe Saint-Pierre GIFTranslator::GIFTranslator() 3185e4c29a6SJohn Scipione : 3195e4c29a6SJohn Scipione BaseTranslator(B_TRANSLATE("GIF images"), 320abfe23dcSPhilippe Saint-Pierre B_TRANSLATE("GIF image translator"), 321abfe23dcSPhilippe Saint-Pierre GIF_TRANSLATOR_VERSION, 322abfe23dcSPhilippe Saint-Pierre sInputFormats, kNumInputFormats, 323abfe23dcSPhilippe Saint-Pierre sOutputFormats, kNumOutputFormats, 324abfe23dcSPhilippe Saint-Pierre "GIFTranslator_Settings", 325abfe23dcSPhilippe Saint-Pierre sDefaultSettings, kNumDefaultSettings, 326abfe23dcSPhilippe Saint-Pierre B_TRANSLATOR_BITMAP, B_GIF_FORMAT) 327abfe23dcSPhilippe Saint-Pierre { 328abfe23dcSPhilippe Saint-Pierre } 329abfe23dcSPhilippe Saint-Pierre 330abfe23dcSPhilippe Saint-Pierre 331abfe23dcSPhilippe Saint-Pierre GIFTranslator::~GIFTranslator() 332abfe23dcSPhilippe Saint-Pierre { 333abfe23dcSPhilippe Saint-Pierre } 334abfe23dcSPhilippe Saint-Pierre 335abfe23dcSPhilippe Saint-Pierre 336abfe23dcSPhilippe Saint-Pierre BView* 337abfe23dcSPhilippe Saint-Pierre GIFTranslator::NewConfigView(TranslatorSettings* settings) 338abfe23dcSPhilippe Saint-Pierre { 33978bfaa98SJohn Scipione return new(std::nothrow) GIFView(settings); 3409949213aSStephan Aßmus } 3419949213aSStephan Aßmus 3429949213aSStephan Aßmus 3439949213aSStephan Aßmus int 3449949213aSStephan Aßmus main() 3459949213aSStephan Aßmus { 346abfe23dcSPhilippe Saint-Pierre BApplication app("application/x-vnd.Haiku-GIFTranslator"); 34778bfaa98SJohn Scipione status_t result = LaunchTranslatorWindow(new(std::nothrow) GIFTranslator, 348abfe23dcSPhilippe Saint-Pierre B_TRANSLATE("GIF Settings"), kRectView); 349abfe23dcSPhilippe Saint-Pierre if (result == B_OK) { 350abfe23dcSPhilippe Saint-Pierre app.Run(); 3519949213aSStephan Aßmus return 0; 3525e4c29a6SJohn Scipione } 3535e4c29a6SJohn Scipione 354abfe23dcSPhilippe Saint-Pierre return 1; 3559949213aSStephan Aßmus } 356