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