1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_linguistic.hxx" 30 #include <tools/urlobj.hxx> 31 #include <tools/debug.hxx> 32 #include <tools/fsys.hxx> 33 #include <tools/string.hxx> 34 #include <i18npool/mslangid.hxx> 35 #include <tools/stream.hxx> 36 #include <osl/mutex.hxx> 37 #include <unotools/processfactory.hxx> 38 #include <ucbhelper/content.hxx> 39 40 #include <cppuhelper/factory.hxx> // helper for factories 41 #include <com/sun/star/linguistic2/XConversionDictionary.hpp> 42 #include <com/sun/star/linguistic2/ConversionDictionaryType.hpp> 43 #include <com/sun/star/linguistic2/ConversionPropertyType.hpp> 44 #include <com/sun/star/util/XFlushable.hpp> 45 #include <com/sun/star/lang/Locale.hpp> 46 #include <com/sun/star/lang/EventObject.hpp> 47 #ifndef _COM_SUN_STAR_UNO_REFERENCE_HPP_ 48 #include <com/sun/star/uno/Reference.h> 49 #endif 50 #include <com/sun/star/registry/XRegistryKey.hpp> 51 #include <com/sun/star/util/XFlushListener.hpp> 52 #include <com/sun/star/io/XActiveDataSource.hpp> 53 #include <com/sun/star/document/XFilter.hpp> 54 #include <com/sun/star/beans/PropertyValue.hpp> 55 #include <xmloff/nmspmap.hxx> 56 #include <xmloff/xmlnmspe.hxx> 57 #include <unotools/streamwrap.hxx> 58 59 #include "convdic.hxx" 60 #include "convdicxml.hxx" 61 #include "linguistic/misc.hxx" 62 #include "defs.hxx" 63 64 using namespace std; 65 using namespace utl; 66 using namespace osl; 67 using namespace rtl; 68 using namespace com::sun::star; 69 using namespace com::sun::star::lang; 70 using namespace com::sun::star::uno; 71 using namespace com::sun::star::linguistic2; 72 using namespace linguistic; 73 74 #define XML_NAMESPACE_TCD_STRING "http://openoffice.org/2003/text-conversion-dictionary" 75 #define CONV_TYPE_HANGUL_HANJA "Hangul / Hanja" 76 #define CONV_TYPE_SCHINESE_TCHINESE "Chinese simplified / Chinese traditional" 77 78 /////////////////////////////////////////////////////////////////////////// 79 80 static const OUString ConversionTypeToText( sal_Int16 nConversionType ) 81 { 82 OUString aRes; 83 if (nConversionType == ConversionDictionaryType::HANGUL_HANJA) 84 aRes = A2OU( CONV_TYPE_HANGUL_HANJA ); 85 else if (nConversionType == ConversionDictionaryType::SCHINESE_TCHINESE) 86 aRes = A2OU( CONV_TYPE_SCHINESE_TCHINESE ); 87 return aRes; 88 } 89 90 static sal_Int16 GetConversionTypeFromText( const String &rText ) 91 { 92 sal_Int16 nRes = -1; 93 if (rText.EqualsAscii( CONV_TYPE_HANGUL_HANJA )) 94 nRes = ConversionDictionaryType::HANGUL_HANJA; 95 else if (rText.EqualsAscii( CONV_TYPE_SCHINESE_TCHINESE )) 96 nRes = ConversionDictionaryType::SCHINESE_TCHINESE; 97 return nRes; 98 } 99 100 /////////////////////////////////////////////////////////////////////////// 101 102 class ConvDicXMLImportContext : 103 public SvXMLImportContext 104 { 105 public: 106 ConvDicXMLImportContext( 107 ConvDicXMLImport &rImport, 108 sal_uInt16 nPrfx, const OUString& rLName ) : 109 SvXMLImportContext( rImport, nPrfx, rLName ) 110 { 111 } 112 113 const ConvDicXMLImport & GetConvDicImport() const 114 { 115 return (const ConvDicXMLImport &) GetImport(); 116 } 117 118 ConvDicXMLImport & GetConvDicImport() 119 { 120 return (ConvDicXMLImport &) GetImport(); 121 } 122 123 // SvXMLImportContext 124 virtual void Characters( const OUString &rChars ); 125 virtual SvXMLImportContext * CreateChildContext( sal_uInt16 nPrefix, const OUString& rLocalName, const uno::Reference< xml::sax::XAttributeList > &rxAttrList); 126 }; 127 128 129 class ConvDicXMLDictionaryContext_Impl : 130 public ConvDicXMLImportContext 131 { 132 sal_Int16 nLanguage; 133 sal_Int16 nConversionType; 134 135 public: 136 ConvDicXMLDictionaryContext_Impl( ConvDicXMLImport &rImport, 137 sal_uInt16 nPrefix, const OUString& rLName) : 138 ConvDicXMLImportContext( rImport, nPrefix, rLName ) 139 { 140 nLanguage = LANGUAGE_NONE; 141 nConversionType = -1; 142 } 143 144 // SvXMLImportContext 145 virtual void StartElement( const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XAttributeList >& xAttrList ); 146 virtual SvXMLImportContext * CreateChildContext( sal_uInt16 nPrefix, const OUString& rLocalName, const uno::Reference< xml::sax::XAttributeList > &rxAttrList ); 147 148 sal_Int16 GetLanguage() const { return nLanguage; } 149 sal_Int16 GetConversionType() const { return nConversionType; } 150 }; 151 152 153 class ConvDicXMLEntryTextContext_Impl : 154 public ConvDicXMLImportContext 155 { 156 OUString aLeftText; 157 sal_Int16 nPropertyType; // used for Chinese simplified/traditional conversion 158 ConvDicXMLDictionaryContext_Impl &rDicContext; 159 160 public: 161 ConvDicXMLEntryTextContext_Impl( 162 ConvDicXMLImport &rImport, 163 sal_uInt16 nPrefix, const OUString& rLName, 164 ConvDicXMLDictionaryContext_Impl &rParentContext ) : 165 ConvDicXMLImportContext( rImport, nPrefix, rLName ), 166 nPropertyType( ConversionPropertyType::NOT_DEFINED ), 167 rDicContext( rParentContext ) 168 { 169 } 170 171 // SvXMLImportContext 172 virtual void StartElement( const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XAttributeList >& xAttrList ); 173 virtual SvXMLImportContext * CreateChildContext( sal_uInt16 nPrefix, const OUString& rLocalName, const uno::Reference< xml::sax::XAttributeList > &rxAttrList ); 174 175 const OUString & GetLeftText() const { return aLeftText; } 176 sal_Int16 GetPropertyType() const { return nPropertyType; } 177 void SetPropertyType( sal_Int16 nVal ) { nPropertyType = nVal; } 178 }; 179 180 181 class ConvDicXMLRightTextContext_Impl : 182 public ConvDicXMLImportContext 183 { 184 OUString aRightText; 185 ConvDicXMLEntryTextContext_Impl &rEntryContext; 186 187 public: 188 ConvDicXMLRightTextContext_Impl( 189 ConvDicXMLImport &rImport, 190 sal_uInt16 nPrefix, const OUString& rLName, 191 ConvDicXMLEntryTextContext_Impl &rParentContext ) : 192 ConvDicXMLImportContext( rImport, nPrefix, rLName ), 193 rEntryContext( rParentContext ) 194 { 195 } 196 197 // SvXMLImportContext 198 virtual void EndElement(); 199 virtual SvXMLImportContext * CreateChildContext( sal_uInt16 nPrefix, const OUString& rLocalName, const uno::Reference< xml::sax::XAttributeList > &rxAttrList ); 200 virtual void Characters( const OUString &rChars ); 201 202 const OUString & GetRightText() const { return aRightText; } 203 const OUString & GetLeftText() const { return rEntryContext.GetLeftText(); } 204 ConvDic * GetDic() { return GetConvDicImport().GetDic(); } 205 }; 206 207 /////////////////////////////////////////////////////////////////////////// 208 209 void ConvDicXMLImportContext::Characters(const OUString & /*rChars*/) 210 { 211 /* 212 Whitespace occurring within the content of token elements is "trimmed" 213 from the ends (i.e. all whitespace at the beginning and end of the 214 content is removed), and "collapsed" internally (i.e. each sequence of 215 1 or more whitespace characters is replaced with one blank character). 216 */ 217 //collapsing not done yet! 218 219 // warning-free code: since the result is not used there is no need for trimming... 220 //const OUString &rChars2 = rChars.trim(); 221 } 222 223 SvXMLImportContext * ConvDicXMLImportContext::CreateChildContext( 224 sal_uInt16 nPrefix, const OUString& rLocalName, 225 const uno::Reference< xml::sax::XAttributeList > & /*rxAttrList*/ ) 226 { 227 SvXMLImportContext *pContext = 0; 228 if (nPrefix == XML_NAMESPACE_TCD && rLocalName.equalsAscii( "text-conversion-dictionary" )) 229 pContext = new ConvDicXMLDictionaryContext_Impl( GetConvDicImport(), nPrefix, rLocalName ); 230 else 231 pContext = new SvXMLImportContext( GetImport(), nPrefix, rLocalName ); 232 return pContext; 233 } 234 235 //////////////////////////////////////// 236 237 void ConvDicXMLDictionaryContext_Impl::StartElement( 238 const uno::Reference< xml::sax::XAttributeList > &rxAttrList ) 239 { 240 sal_Int16 nAttrCount = rxAttrList.is() ? rxAttrList->getLength() : 0; 241 for (sal_Int16 i = 0; i < nAttrCount; ++i) 242 { 243 OUString aAttrName = rxAttrList->getNameByIndex(i); 244 OUString aLocalName; 245 sal_uInt16 nPrefix = GetImport().GetNamespaceMap(). 246 GetKeyByAttrName( aAttrName, &aLocalName ); 247 OUString aValue = rxAttrList->getValueByIndex(i); 248 249 if (nPrefix == XML_NAMESPACE_TCD && aLocalName.equalsAscii( "lang" )) 250 nLanguage = MsLangId::convertIsoStringToLanguage( aValue ); 251 else if (nPrefix == XML_NAMESPACE_TCD && aLocalName.equalsAscii( "conversion-type" )) 252 nConversionType = GetConversionTypeFromText( aValue ); 253 } 254 GetConvDicImport().SetLanguage( nLanguage ); 255 GetConvDicImport().SetConversionType( nConversionType ); 256 257 //!! hack to stop the parser from reading the rest of the file !! 258 //!! when only the header (language, conversion type) is needed !! 259 // if (GetConvDicImport().GetDic() == 0) 260 // throw uno::RuntimeException(); 261 } 262 263 SvXMLImportContext * ConvDicXMLDictionaryContext_Impl::CreateChildContext( 264 sal_uInt16 nPrefix, const OUString& rLocalName, 265 const uno::Reference< xml::sax::XAttributeList > & /*rxAttrList*/ ) 266 { 267 SvXMLImportContext *pContext = 0; 268 if (nPrefix == XML_NAMESPACE_TCD && rLocalName.equalsAscii( "entry" )) 269 pContext = new ConvDicXMLEntryTextContext_Impl( GetConvDicImport(), nPrefix, rLocalName, *this ); 270 else 271 pContext = new SvXMLImportContext( GetImport(), nPrefix, rLocalName ); 272 return pContext; 273 } 274 275 //////////////////////////////////////// 276 277 SvXMLImportContext * ConvDicXMLEntryTextContext_Impl::CreateChildContext( 278 sal_uInt16 nPrefix, const OUString& rLocalName, 279 const uno::Reference< xml::sax::XAttributeList > & /*rxAttrList*/ ) 280 { 281 SvXMLImportContext *pContext = 0; 282 if (nPrefix == XML_NAMESPACE_TCD && rLocalName.equalsAscii( "right-text" )) 283 pContext = new ConvDicXMLRightTextContext_Impl( GetConvDicImport(), nPrefix, rLocalName, *this ); 284 else 285 pContext = new SvXMLImportContext( GetImport(), nPrefix, rLocalName ); 286 return pContext; 287 } 288 289 void ConvDicXMLEntryTextContext_Impl::StartElement( 290 const uno::Reference< xml::sax::XAttributeList >& rxAttrList ) 291 { 292 sal_Int16 nAttrCount = rxAttrList.is() ? rxAttrList->getLength() : 0; 293 for (sal_Int16 i = 0; i < nAttrCount; ++i) 294 { 295 OUString aAttrName = rxAttrList->getNameByIndex(i); 296 OUString aLocalName; 297 sal_uInt16 nPrefix = GetImport().GetNamespaceMap(). 298 GetKeyByAttrName( aAttrName, &aLocalName ); 299 OUString aValue = rxAttrList->getValueByIndex(i); 300 301 if (nPrefix == XML_NAMESPACE_TCD && aLocalName.equalsAscii( "left-text" )) 302 aLeftText = aValue; 303 if (nPrefix == XML_NAMESPACE_TCD && aLocalName.equalsAscii( "property-type" )) 304 nPropertyType = (sal_Int16) aValue.toInt32(); 305 } 306 } 307 308 //////////////////////////////////////// 309 310 SvXMLImportContext * ConvDicXMLRightTextContext_Impl::CreateChildContext( 311 sal_uInt16 nPrefix, const OUString& rLocalName, 312 const uno::Reference< xml::sax::XAttributeList > & /*rxAttrList*/ ) 313 { 314 // leaf: return default (empty) context 315 SvXMLImportContext *pContext = new SvXMLImportContext( GetImport(), nPrefix, rLocalName ); 316 return pContext; 317 } 318 319 void ConvDicXMLRightTextContext_Impl::Characters( const OUString &rChars ) 320 { 321 aRightText += rChars; 322 } 323 324 void ConvDicXMLRightTextContext_Impl::EndElement() 325 { 326 ConvDic *pDic = GetDic(); 327 if (pDic) 328 pDic->AddEntry( GetLeftText(), GetRightText() ); 329 } 330 331 332 /////////////////////////////////////////////////////////////////////////// 333 334 sal_Bool ConvDicXMLExport::Export() 335 { 336 sal_Bool bRet = sal_False; 337 338 uno::Reference< document::XExporter > xExporter( this ); 339 uno::Reference< document::XFilter > xFilter( xExporter, UNO_QUERY ); 340 uno::Sequence< beans::PropertyValue > aProps(0); 341 xFilter->filter( aProps ); // calls exportDoc implicitly 342 343 return bRet = bSuccess; 344 } 345 346 347 sal_uInt32 ConvDicXMLExport::exportDoc( enum ::xmloff::token::XMLTokenEnum /*eClass*/ ) 348 { 349 _GetNamespaceMap().Add( A2OU( "tcd" ), 350 A2OU( XML_NAMESPACE_TCD_STRING ), XML_NAMESPACE_TCD ); 351 352 GetDocHandler()->startDocument(); 353 354 // Add xmlns line and some other arguments 355 AddAttribute( _GetNamespaceMap().GetAttrNameByKey( XML_NAMESPACE_TCD ), 356 _GetNamespaceMap().GetNameByKey( XML_NAMESPACE_TCD ) ); 357 AddAttributeASCII( XML_NAMESPACE_TCD, "package", "org.openoffice.Office" ); 358 359 OUString aIsoLang( MsLangId::convertLanguageToIsoString( rDic.nLanguage ) ); 360 AddAttribute( XML_NAMESPACE_TCD, "lang", aIsoLang ); 361 OUString aConvType( ConversionTypeToText( rDic.nConversionType ) ); 362 AddAttribute( XML_NAMESPACE_TCD, "conversion-type", aConvType ); 363 364 //!! block necessary in order to have SvXMLElementExport d-tor called 365 //!! before the call to endDocument 366 { 367 SvXMLElementExport aRoot( *this, XML_NAMESPACE_TCD, "text-conversion-dictionary", sal_True, sal_True ); 368 _ExportContent(); 369 } 370 371 GetDocHandler()->endDocument(); 372 373 bSuccess = sal_True; 374 return 0; 375 } 376 377 378 void ConvDicXMLExport::_ExportContent() 379 { 380 // aquire sorted list of all keys 381 ConvMapKeySet aKeySet; 382 ConvMap::iterator aIt; 383 for (aIt = rDic.aFromLeft.begin(); aIt != rDic.aFromLeft.end(); ++aIt) 384 aKeySet.insert( (*aIt).first ); 385 386 ConvMapKeySet::iterator aKeyIt; 387 for (aKeyIt = aKeySet.begin(); aKeyIt != aKeySet.end(); ++aKeyIt) 388 { 389 OUString aLeftText( *aKeyIt ); 390 AddAttribute( XML_NAMESPACE_TCD, "left-text", aLeftText ); 391 if (rDic.pConvPropType.get()) // property-type list available? 392 { 393 sal_Int16 nPropertyType = -1; 394 PropTypeMap::iterator aIt2 = rDic.pConvPropType->find( aLeftText ); 395 if (aIt2 != rDic.pConvPropType->end()) 396 nPropertyType = (*aIt2).second; 397 DBG_ASSERT( nPropertyType, "property-type not found" ); 398 if (nPropertyType == -1) 399 nPropertyType = ConversionPropertyType::NOT_DEFINED; 400 AddAttribute( XML_NAMESPACE_TCD, "property-type", OUString::valueOf( (sal_Int32) nPropertyType ) ); 401 } 402 SvXMLElementExport aEntryMain( *this, XML_NAMESPACE_TCD, 403 "entry" , sal_True, sal_True ); 404 405 pair< ConvMap::iterator, ConvMap::iterator > aRange = 406 rDic.aFromLeft.equal_range( *aKeyIt ); 407 for (aIt = aRange.first; aIt != aRange.second; ++aIt) 408 { 409 DBG_ASSERT( *aKeyIt == (*aIt).first, "key <-> entry mismatch" ); 410 OUString aRightText( (*aIt).second ); 411 SvXMLElementExport aEntryRightText( *this, XML_NAMESPACE_TCD, 412 "right-text" , sal_True, sal_False ); 413 Characters( aRightText ); 414 } 415 } 416 } 417 418 ::rtl::OUString SAL_CALL ConvDicXMLExport::getImplementationName() 419 throw( uno::RuntimeException ) 420 { 421 return A2OU( "com.sun.star.lingu2.ConvDicXMLExport" ); 422 } 423 424 /////////////////////////////////////////////////////////////////////////// 425 426 void SAL_CALL ConvDicXMLImport::startDocument(void) 427 throw( xml::sax::SAXException, uno::RuntimeException ) 428 { 429 // register namespace at first possible opportunity 430 GetNamespaceMap().Add( A2OU( "tcd" ), 431 A2OU( XML_NAMESPACE_TCD_STRING ), XML_NAMESPACE_TCD ); 432 SvXMLImport::startDocument(); 433 } 434 435 void SAL_CALL ConvDicXMLImport::endDocument(void) 436 throw( xml::sax::SAXException, uno::RuntimeException ) 437 { 438 SvXMLImport::endDocument(); 439 } 440 441 SvXMLImportContext * ConvDicXMLImport::CreateContext( 442 sal_uInt16 nPrefix, 443 const rtl::OUString &rLocalName, 444 const uno::Reference < xml::sax::XAttributeList > & /*rxAttrList*/ ) 445 { 446 SvXMLImportContext *pContext = 0; 447 if (nPrefix == XML_NAMESPACE_TCD && rLocalName.equalsAscii( "text-conversion-dictionary" )) 448 pContext = new ConvDicXMLDictionaryContext_Impl( *this, nPrefix, rLocalName ); 449 else 450 pContext = new SvXMLImportContext( *this, nPrefix, rLocalName ); 451 return pContext; 452 } 453 454 455 OUString SAL_CALL ConvDicXMLImport::getImplementationName() 456 throw( uno::RuntimeException ) 457 { 458 return A2OU( "com.sun.star.lingu2.ConvDicXMLImport" ); 459 } 460 461 /////////////////////////////////////////////////////////////////////////// 462 463