/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#include <stdio.h>


#include <vcl/graph.hxx>
#include <bf_so3/svstor.hxx>
#include <bf_so3/embobj.hxx>
#include <bf_so3/ipobj.hxx>
#include <sot/exchange.hxx>

namespace binfilter {

// Vordefinierte OLE-1-IDs
// Unter Windows koennen wir uns noch auf die RegDB stuerzen, sonst
// nehmen wir eben diese IDs
// Standardformat:

//     0003xxxx-0000-0000-C000-000000000046

struct ClsIDs {
    UINT32      nId;
    const sal_Char* pSvrName;
    const sal_Char* pDspName;
} aClsIDs[] = {

    { 0x000212F0, "MSWordArt",          "Microsoft Word Art"            },
    { 0x000212F0, "MSWordArt.2",        "Microsoft Word Art 2.0"        },

    // MS Apps
    { 0x00030000, "ExcelWorksheet",     "Microsoft Excel Worksheet"     },
    { 0x00030001, "ExcelChart",         "Microsoft Excel Chart"         },
    { 0x00030002, "ExcelMacrosheet",    "Microsoft Excel Macro"         },
    { 0x00030003, "WordDocument",       "Microsoft Word Document"       },
    { 0x00030004, "MSPowerPoint",       "Microsoft PowerPoint"          },
    { 0x00030005, "MSPowerPointSho",    "Microsoft PowerPoint Slide Show"},
    { 0x00030006, "MSGraph",            "Microsoft Graph"               },
    { 0x00030007, "MSDraw",             "Microsoft Draw"                },
    { 0x00030008, "Note-It",            "Microsoft Note-It"             },
    { 0x00030009, "WordArt",            "Microsoft Word Art"            },
    { 0x0003000a, "PBrush",             "Microsoft PaintBrush Picture"  },
    { 0x0003000b, "Equation",           "Microsoft Equation Editor"     },
    { 0x0003000c, "Package",            "Package"                       },
    { 0x0003000d, "SoundRec",           "Sound"                         },
    { 0x0003000e, "MPlayer",            "Media Player"                  },
    // MS Demos
    { 0x0003000f, "ServerDemo",         "OLE 1.0 Server Demo"           },
    { 0x00030010, "Srtest",             "OLE 1.0 Test Demo"             },
    { 0x00030011, "SrtInv",             "OLE 1.0 Inv Demo"              },
    { 0x00030012, "OleDemo",            "OLE 1.0 Demo"                  },

    // Coromandel / Dorai Swamy / 718-793-7963
    { 0x00030013, "CoromandelIntegra",  "Coromandel Integra"            },
    { 0x00030014, "CoromandelObjServer","Coromandel Object Server"      },

    // 3-d Visions Corp / Peter Hirsch / 310-325-1339
    { 0x00030015, "StanfordGraphics",   "Stanford Graphics"             },

    // Deltapoint / Nigel Hearne / 408-648-4000
    { 0x00030016, "DGraphCHART",        "DeltaPoint Graph Chart"        },
    { 0x00030017, "DGraphDATA",         "DeltaPoint Graph Data"         },

    // Corel / Richard V. Woodend / 613-728-8200 x1153
    { 0x00030018, "PhotoPaint",         "Corel PhotoPaint"              },
    { 0x00030019, "CShow",              "Corel Show"                    },
    { 0x0003001a, "CorelChart",         "Corel Chart"                   },
    { 0x0003001b, "CDraw",              "Corel Draw"                    },

    // Inset Systems / Mark Skiba / 203-740-2400
    { 0x0003001c, "HJWIN1.0",           "Inset Systems"                 },

    // Mark V Systems / Mark McGraw / 818-995-7671
    { 0x0003001d, "ObjMakerOLE",        "MarkV Systems Object Maker"    },

    // IdentiTech / Mike Gilger / 407-951-9503
    { 0x0003001e, "FYI",                "IdentiTech FYI"                },
    { 0x0003001f, "FYIView",            "IdentiTech FYI Viewer"         },

    // Inventa Corporation / Balaji Varadarajan / 408-987-0220
    { 0x00030020, "Stickynote",         "Inventa Sticky Note"           },

    // ShapeWare Corp. / Lori Pearce / 206-467-6723
    { 0x00030021, "ShapewareVISIO10",   "Shapeware Visio 1.0"           },
    { 0x00030022, "ImportServer",       "Spaheware Import Server"       },

    // test app SrTest
    { 0x00030023, "SrvrTest",           "OLE 1.0 Server Test"           },

    // test app ClTest.  Doesn't really work as a server but is in reg db
    { 0x00030025, "Cltest",             "OLE 1.0 Client Test"           },

    // Microsoft ClipArt Gallery   Sherry Larsen-Holmes
    { 0x00030026, "MS_ClipArt_Gallery", "Microsoft ClipArt Gallery"     },
    // Microsoft Project  Cory Reina
    { 0x00030027, "MSProject",          "Microsoft Project"             },

    // Microsoft Works Chart
    { 0x00030028, "MSWorksChart",       "Microsoft Works Chart"         },

    // Microsoft Works Spreadsheet
    { 0x00030029, "MSWorksSpreadsheet", "Microsoft Works Spreadsheet"   },

    // AFX apps - Dean McCrory
    { 0x0003002A, "MinSvr",             "AFX Mini Server"               },
    { 0x0003002B, "HierarchyList",      "AFX Hierarchy List"            },
    { 0x0003002C, "BibRef",             "AFX BibRef"                    },
    { 0x0003002D, "MinSvrMI",           "AFX Mini Server MI"            },
    { 0x0003002E, "TestServ",           "AFX Test Server"               },

    // Ami Pro
    { 0x0003002F, "AmiProDocument",     "Ami Pro Document"              },

    // WordPerfect Presentations For Windows
    { 0x00030030, "WPGraphics",         "WordPerfect Presentation"      },
    { 0x00030031, "WPCharts",           "WordPerfect Chart"             },

    // MicroGrafx Charisma
    { 0x00030032, "Charisma",           "MicroGrafx Charisma"           },
    { 0x00030033, "Charisma_30",        "MicroGrafx Charisma 3.0"       },
    { 0x00030034, "CharPres_30",        "MicroGrafx Charisma 3.0 Pres"  },
    // MicroGrafx Draw
    { 0x00030035, "Draw",               "MicroGrafx Draw"               },
    // MicroGrafx Designer
    { 0x00030036, "Designer_40",        "MicroGrafx Designer 4.0"       },

    // STAR DIVISION
//  { 0x000424CA, "StarMath",           "StarMath 1.0"                  },
    { 0x00043AD2, "FontWork",           "Star FontWork"                 },
//  { 0x000456EE, "StarMath2",          "StarMath 2.0"                  },

    { 0, "", "" } };

// Da wir nicht die gesamte SO-Lib inklusive OLE1 dran haben wollen,
// sei hier die Leseroutine fuer ein StarObject noch mit drin.

#define SO_SIGNATURE 0x534F6D64             // Signatur ('mdSO' im INTEL-Format)
#define SO_VERSION   0x00000002

struct StarObjectFileHdr
{
    UINT32  nSize;                          // Groesse der Struktur
    UINT32  nSignature;                     // Signatur
    UINT32  nVersion;                       // Version
    UINT32  nWidth;                         // Breite in 1/100 mm
    UINT32  nHeight;                        // Hoehe in 1/100 mm
    UINT32  nObjName;                       // Laenge Objektname
    UINT32  nServerName;                    // Laenge Servername
    UINT32  nPrivData;                      // Laenge private Daten
    UINT32  nPicData;                       // Laenge GDIMetafile
};

// Laden eines StarObjects. Die Daten werden in den Parametern
// uebergeben, der Returnwert ist der Stream-Fehlercode.
#define PIC_READ    1
#define DATA_READ   2
static ULONG LoadStarObject
    ( SvStream& rSrc, String& rSvrName, String& rObjName,
      GDIMetaFile & rPic, SvStream & rDataStm )
{
    ULONG nRet = 0;
    StarObjectFileHdr aHdr;
    long pos = rSrc.Tell();
    aHdr.nSize = 0L;
    rSrc >> aHdr.nSize;
    rSrc.Seek( pos );

    if ( aHdr.nSize != sizeof( aHdr ) )
    {
        rSrc.SetError( SVSTREAM_GENERALERROR );
        return 0;
    }

    rSrc >> aHdr.nSize
         >> aHdr.nSignature
         >> aHdr.nVersion
         >> aHdr.nWidth
         >> aHdr.nHeight
         >> aHdr.nObjName
         >> aHdr.nServerName
         >> aHdr.nPrivData
         >> aHdr.nPicData;

    if ( aHdr.nSignature != SO_SIGNATURE || aHdr.nVersion > SO_VERSION )
    {
        rSrc.SetError( SVSTREAM_GENERALERROR );
        return 0;
    }

    sal_Char cBuf[ 128 ];
    rSrc.Read( cBuf, aHdr.nObjName );
    if ( rSrc.GetError() )
        return 0;
    rObjName = String(
        cBuf, sal::static_int_cast< xub_StrLen >( aHdr.nObjName ),
        osl_getThreadTextEncoding() );

    rSrc.Read( cBuf, aHdr.nServerName );
    if ( rSrc.GetError() )
        return 0;
    rSvrName = String(
        cBuf, sal::static_int_cast< xub_StrLen >( aHdr.nServerName ),
        osl_getThreadTextEncoding() );
    if ( aHdr.nPrivData )
    {
        UINT32 nLen;
        rSrc >> nLen;
        if ( rSrc.GetError() )
            return 0;

        BYTE * pData = new BYTE[ nLen ];
        rDataStm << nLen;
        rSrc.Read( pData, nLen );
        rDataStm.Write( pData, nLen );
        delete [] pData;
        if ( rDataStm.GetError() )
        {
            rSrc.SetError( rDataStm.GetError() );
            return 0;
        }
        nRet = DATA_READ;
    }
    if ( aHdr.nPicData )
    {
        if( aHdr.nVersion < SO_VERSION )
        {
            // Alte Grafiken
            rSrc >> rPic;
        }
        else
        {
            // neue, portable oder nicht portable Grafiken
            Graphic aGrf;
            aGrf.ReadEmbedded( rSrc );
            rPic = aGrf.GetGDIMetaFile();
        }
        nRet |= PIC_READ;
    }
    if ( rSrc.GetError() )
        return 0;
    return nRet;
}

BOOL SvEmbeddedObject::InsertStarObject
    ( const String &rObjName, const String& rStgName,
      SvStream& rSrc, SvPersist* pPersist )
{
    ULONG nRead;
    SvStorageRef rpDst( pPersist->GetStorage() );
    String aObjName, aSvrName;
    GDIMetaFile aPic;
    SvMemoryStream aDataStm;

    nRead = LoadStarObject( rSrc, aSvrName, aObjName, aPic, aDataStm );
    if( rSrc.GetError() != SVSTREAM_OK )
        return FALSE;

    // Es kann losgehen!
    // Erstmal den ClassID sowie die Bschreibung suchen
    ClsIDs* pIds;
    for( pIds = aClsIDs; pIds->nId; pIds++ )
    {
        if( COMPARE_EQUAL == aSvrName.CompareToAscii( pIds->pSvrName ) )
            break;
    }
    SvGlobalName* pClsId = NULL;
    String aShort, aFull;
    if( pIds->nId )
    {
        // gefunden!
        pClsId = new SvGlobalName( pIds->nId, 0, 0, 0xc0,0,0,0,0,0,0,0x46 );
        aFull = String( pIds->pDspName, osl_getThreadTextEncoding() );
        aShort = aSvrName;
    }
    else if( (COMPARE_EQUAL == aSvrName.CompareToAscii( "StarMath2" ))
        || (COMPARE_EQUAL == aSvrName.CompareToAscii( "StarMath" )) )
    {
        // Sonderfall: In StarMath 3 umwandeln
        pClsId = new SvGlobalName;
        pClsId->MakeId( String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM( "D4590460-35FD-101C-B12A-04021C007002" ) ) );
        aFull = String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM( "StarMath 3.0" ) );
        aShort = String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM( "StarMath" ) );
    }

    if( !pClsId )
    {
        rpDst->SetError( SVSTREAM_GENERALERROR );
        return FALSE;
    }

    // Class-ID und Daten sind vorhanden. Nun muss noch der Storage
    // aufgebaut werden.
    // Main Storage einrichten
    if( rpDst->IsContained( rStgName ) )
        rpDst->Remove( rStgName );
    SvStorageRef rpObj = rpDst->OpenOLEStorage( rStgName,
                            STREAM_READWRITE| STREAM_SHARE_DENYALL );
//  SvStorageRef rpObj = rpDst->OpenStorage( rStgName,
//                          STREAM_READWRITE| STREAM_SHARE_DENYALL );
    if( rpObj.Is() && rpObj->GetError() )
    {
        rpDst->SetError( rpObj->GetError() ); rpObj.Clear();
    }
    if( rpObj.Is() )
    {
        // 1. die OLE-Daten
        ULONG nCbFmt = SotExchange::RegisterFormatName( aShort );
        rpObj->SetClass( *pClsId, nCbFmt, aFull );
    }
    delete pClsId;

    // 2. Den Daten-Stream aufsetzen
    if( rpObj.Is() && (nRead & DATA_READ) )
    {
        SvStorageStreamRef rpStrm =
            rpObj->OpenStream( String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM( "\1Ole10Native" ) ),
                            STREAM_WRITE| STREAM_SHARE_DENYALL );
        if( rpStrm.Is() && rpStrm->GetError() )
        {
            rpDst->SetError( rpStrm->GetError() ); rpStrm.Clear();
        }
        if( rpStrm.Is() )
        {
            aDataStm.Seek( 0 );
            *rpStrm << aDataStm;
            rpDst->SetError( rpObj->GetError() );
            if( rpDst->GetError() )
                rpObj.Clear();
        }
    }

    // 3. Den Picture-Stream aufsetzen
    if( rpObj.Is() && (nRead & PIC_READ) )
    {
        ULONG nErr = SVSTREAM_OK;
        if( !SvEmbeddedObject::MakeContentStream( rpObj, aPic ) )
            nErr = SVSTREAM_WRITE_ERROR;
        else
            nErr = rpObj->GetError();
        rpDst->SetError( nErr );
        if( nErr != SVSTREAM_OK )
            rpObj.Clear();
    }

    // 4. Alles committen
    if( rpObj.Is() )
    {
        rpObj->Commit();
        rpDst->SetError( rpObj->GetError() );
    }
    // Sonst evtl. den (defekten) Storage weg
    else if( rpDst->IsContained( rStgName ) )
        rpDst->Remove( rStgName );
    rpDst->Commit();
    if( rpDst->GetError() == SVSTREAM_OK )
    {
        SvObjectRef rpOleObj =
            ((SvFactory*)SvInPlaceObject::ClassFactory())->CreateAndLoad( rpObj );
        SvInPlaceObjectRef rpInplaceObj( &rpOleObj );
        if( rpInplaceObj.Is() )
        {
            SvInfoObjectRef rpInfo =
                new SvEmbeddedInfoObject( rpInplaceObj, rObjName );
            return pPersist->Insert( rpInfo );
        }
    }
    return FALSE;
}

// Laden des Pictures eines StarObjects
// (falls es nicht als OLE-Objekt ladbar ist)

BOOL SvEmbeddedObject::LoadStarObjectPicture( SvStream& rSrc, GDIMetaFile& rMTF )
{
    String aObjName, aSvrName;
    GDIMetaFile  aPic;
    SvMemoryStream aDataStm;

    ULONG nErr = LoadStarObject( rSrc, aSvrName, aObjName, aPic, aDataStm );
    (void)nErr;
    if( rSrc.GetError() != SVSTREAM_OK )
        return FALSE;

    rMTF = aPic;
    return TRUE;
}

}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
