Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

HelperFunctions.cs 28KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755
  1. /*************************************************************************************
  2. DocX – DocX is the community edition of Xceed Words for .NET
  3. Copyright (C) 2009-2016 Xceed Software Inc.
  4. This program is provided to you under the terms of the Microsoft Public
  5. License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license
  6. For more features and fast professional support,
  7. pick up Xceed Words for .NET at https://xceed.com/xceed-words-for-net/
  8. ***********************************************************************************/
  9. using System;
  10. using System.Collections.Generic;
  11. using System.Linq;
  12. using System.Text;
  13. using System.IO.Packaging;
  14. using System.Xml.Linq;
  15. using System.IO;
  16. using System.Reflection;
  17. using System.IO.Compression;
  18. using System.Security.Principal;
  19. using System.Globalization;
  20. using System.Xml;
  21. namespace Xceed.Words.NET
  22. {
  23. internal static class HelperFunctions
  24. {
  25. public const string DOCUMENT_DOCUMENTTYPE = "application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml";
  26. public const string TEMPLATE_DOCUMENTTYPE = "application/vnd.openxmlformats-officedocument.wordprocessingml.template.main+xml";
  27. public const string SETTING_DOCUMENTTYPE = "application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml";
  28. internal static void CreateRelsPackagePart( DocX Document, Uri uri )
  29. {
  30. PackagePart pp = Document._package.CreatePart( uri, "application/vnd.openxmlformats-package.relationships+xml", CompressionOption.Maximum );
  31. using( TextWriter tw = new StreamWriter( new PackagePartStream( pp.GetStream() ) ) )
  32. {
  33. XDocument d = new XDocument
  34. (
  35. new XDeclaration( "1.0", "UTF-8", "yes" ),
  36. new XElement( XName.Get( "Relationships", DocX.rel.NamespaceName ) )
  37. );
  38. var root = d.Root;
  39. d.Save( tw );
  40. }
  41. }
  42. internal static int GetSize( XElement Xml )
  43. {
  44. switch( Xml.Name.LocalName )
  45. {
  46. case "tab":
  47. return 1;
  48. case "br":
  49. return 1;
  50. case "t":
  51. goto case "delText";
  52. case "delText":
  53. return Xml.Value.Length;
  54. case "tr":
  55. goto case "br";
  56. case "tc":
  57. goto case "br";
  58. default:
  59. return 0;
  60. }
  61. }
  62. internal static string GetText( XElement e )
  63. {
  64. StringBuilder sb = new StringBuilder();
  65. GetTextRecursive( e, ref sb );
  66. return sb.ToString();
  67. }
  68. internal static void GetTextRecursive( XElement Xml, ref StringBuilder sb )
  69. {
  70. sb.Append( ToText( Xml ) );
  71. if( Xml.HasElements )
  72. foreach( XElement e in Xml.Elements() )
  73. GetTextRecursive( e, ref sb );
  74. }
  75. internal static List<FormattedText> GetFormattedText( XElement e )
  76. {
  77. List<FormattedText> alist = new List<FormattedText>();
  78. GetFormattedTextRecursive( e, ref alist );
  79. return alist;
  80. }
  81. internal static void GetFormattedTextRecursive( XElement Xml, ref List<FormattedText> alist )
  82. {
  83. FormattedText ft = ToFormattedText( Xml );
  84. FormattedText last = null;
  85. if( ft != null )
  86. {
  87. if( alist.Count() > 0 )
  88. last = alist.Last();
  89. if( last != null && last.CompareTo( ft ) == 0 )
  90. {
  91. // Update text of last entry.
  92. last.text += ft.text;
  93. }
  94. else
  95. {
  96. if( last != null )
  97. ft.index = last.index + last.text.Length;
  98. alist.Add( ft );
  99. }
  100. }
  101. if( Xml.HasElements )
  102. foreach( XElement e in Xml.Elements() )
  103. GetFormattedTextRecursive( e, ref alist );
  104. }
  105. internal static FormattedText ToFormattedText( XElement e )
  106. {
  107. // The text representation of e.
  108. String text = ToText( e );
  109. if( text == String.Empty )
  110. return null;
  111. // e is a w:t element, it must exist inside a w:r element or a w:tabs, lets climb until we find it.
  112. while( !e.Name.Equals( XName.Get( "r", DocX.w.NamespaceName ) ) && !e.Name.Equals( XName.Get( "tabs", DocX.w.NamespaceName ) ) )
  113. e = e.Parent;
  114. // e is a w:r element, lets find the rPr element.
  115. XElement rPr = e.Element( XName.Get( "rPr", DocX.w.NamespaceName ) );
  116. FormattedText ft = new FormattedText();
  117. ft.text = text;
  118. ft.index = 0;
  119. ft.formatting = null;
  120. // Return text with formatting.
  121. if( rPr != null )
  122. ft.formatting = Formatting.Parse( rPr );
  123. return ft;
  124. }
  125. internal static string ToText( XElement e )
  126. {
  127. switch( e.Name.LocalName )
  128. {
  129. case "tab":
  130. return "\t";
  131. case "br":
  132. return "\n";
  133. case "t":
  134. goto case "delText";
  135. case "delText":
  136. {
  137. if( e.Parent != null && e.Parent.Name.LocalName == "r" )
  138. {
  139. XElement run = e.Parent;
  140. var rPr = run.Elements().FirstOrDefault( a => a.Name.LocalName == "rPr" );
  141. if( rPr != null )
  142. {
  143. var caps = rPr.Elements().FirstOrDefault( a => a.Name.LocalName == "caps" );
  144. if( caps != null )
  145. return e.Value.ToUpper();
  146. }
  147. }
  148. return e.Value;
  149. }
  150. case "tr":
  151. goto case "br";
  152. case "tc":
  153. goto case "tab";
  154. default:
  155. return "";
  156. }
  157. }
  158. internal static XElement CloneElement( XElement element )
  159. {
  160. return new XElement
  161. (
  162. element.Name,
  163. element.Attributes(),
  164. element.Nodes().Select
  165. (
  166. n =>
  167. {
  168. XElement e = n as XElement;
  169. if( e != null )
  170. return CloneElement( e );
  171. return n;
  172. }
  173. )
  174. );
  175. }
  176. internal static PackagePart CreateOrGetSettingsPart( Package package )
  177. {
  178. PackagePart settingsPart;
  179. var settingsUri = new Uri( "/word/settings.xml", UriKind.Relative );
  180. if( !package.PartExists( settingsUri ) )
  181. {
  182. settingsPart = package.CreatePart( settingsUri, HelperFunctions.SETTING_DOCUMENTTYPE, CompressionOption.Maximum );
  183. var mainDocPart = package.GetParts().Single( p => p.ContentType.Equals( DOCUMENT_DOCUMENTTYPE, StringComparison.CurrentCultureIgnoreCase ) ||
  184. p.ContentType.Equals( TEMPLATE_DOCUMENTTYPE, StringComparison.CurrentCultureIgnoreCase ) );
  185. mainDocPart.CreateRelationship( settingsUri, TargetMode.Internal, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings" );
  186. var settings = XDocument.Parse
  187. ( @"<?xml version='1.0' encoding='utf-8' standalone='yes'?>
  188. <w:settings xmlns:o='urn:schemas-microsoft-com:office:office' xmlns:r='http://schemas.openxmlformats.org/officeDocument/2006/relationships' xmlns:m='http://schemas.openxmlformats.org/officeDocument/2006/math' xmlns:v='urn:schemas-microsoft-com:vml' xmlns:w10='urn:schemas-microsoft-com:office:word' xmlns:w='http://schemas.openxmlformats.org/wordprocessingml/2006/main' xmlns:sl='http://schemas.openxmlformats.org/schemaLibrary/2006/main'>
  189. <w:zoom w:percent='100' />
  190. <w:defaultTabStop w:val='720' />
  191. <w:characterSpacingControl w:val='doNotCompress' />
  192. <w:compat />
  193. <w:rsids>
  194. <w:rsidRoot w:val='00217F62' />
  195. <w:rsid w:val='001915A3' />
  196. <w:rsid w:val='00217F62' />
  197. <w:rsid w:val='00A906D8' />
  198. <w:rsid w:val='00AB5A74' />
  199. <w:rsid w:val='00F071AE' />
  200. </w:rsids>
  201. <m:mathPr>
  202. <m:mathFont m:val='Cambria Math' />
  203. <m:brkBin m:val='before' />
  204. <m:brkBinSub m:val='--' />
  205. <m:smallFrac m:val='off' />
  206. <m:dispDef />
  207. <m:lMargin m:val='0' />
  208. <m:rMargin m:val='0' />
  209. <m:defJc m:val='centerGroup' />
  210. <m:wrapIndent m:val='1440' />
  211. <m:intLim m:val='subSup' />
  212. <m:naryLim m:val='undOvr' />
  213. </m:mathPr>
  214. <w:themeFontLang w:val='en-IE' w:bidi='ar-SA' />
  215. <w:clrSchemeMapping w:bg1='light1' w:t1='dark1' w:bg2='light2' w:t2='dark2' w:accent1='accent1' w:accent2='accent2' w:accent3='accent3' w:accent4='accent4' w:accent5='accent5' w:accent6='accent6' w:hyperlink='hyperlink' w:followedHyperlink='followedHyperlink' />
  216. <w:shapeDefaults>
  217. <o:shapedefaults v:ext='edit' spidmax='2050' />
  218. <o:shapelayout v:ext='edit'>
  219. <o:idmap v:ext='edit' data='1' />
  220. </o:shapelayout>
  221. </w:shapeDefaults>
  222. <w:decimalSymbol w:val='.' />
  223. <w:listSeparator w:val=',' />
  224. </w:settings>"
  225. );
  226. var themeFontLang = settings.Root.Element( XName.Get( "themeFontLang", DocX.w.NamespaceName ) );
  227. themeFontLang.SetAttributeValue( XName.Get( "val", DocX.w.NamespaceName ), CultureInfo.CurrentCulture );
  228. // Save the settings document.
  229. using( TextWriter tw = new StreamWriter( new PackagePartStream( settingsPart.GetStream() ) ) )
  230. {
  231. settings.Save( tw );
  232. }
  233. }
  234. else
  235. {
  236. settingsPart = package.GetPart( settingsUri );
  237. }
  238. return settingsPart;
  239. }
  240. internal static void CreateCustomPropertiesPart( DocX document )
  241. {
  242. var customPropertiesPart = document._package.CreatePart( new Uri( "/docProps/custom.xml", UriKind.Relative ), "application/vnd.openxmlformats-officedocument.custom-properties+xml", CompressionOption.Maximum );
  243. var customPropDoc = new XDocument
  244. (
  245. new XDeclaration( "1.0", "UTF-8", "yes" ),
  246. new XElement
  247. (
  248. XName.Get( "Properties", DocX.customPropertiesSchema.NamespaceName ),
  249. new XAttribute( XNamespace.Xmlns + "vt", DocX.customVTypesSchema )
  250. )
  251. );
  252. using( TextWriter tw = new StreamWriter( new PackagePartStream( customPropertiesPart.GetStream( FileMode.Create, FileAccess.Write ) ) ) )
  253. {
  254. customPropDoc.Save( tw, SaveOptions.None );
  255. }
  256. document._package.CreateRelationship( customPropertiesPart.Uri, TargetMode.Internal, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/custom-properties" );
  257. }
  258. internal static XDocument DecompressXMLResource( string manifest_resource_name )
  259. {
  260. // XDocument to load the compressed Xml resource into.
  261. XDocument document;
  262. // Get a reference to the executing assembly.
  263. Assembly assembly = Assembly.GetExecutingAssembly();
  264. // Open a Stream to the embedded resource.
  265. Stream stream = assembly.GetManifestResourceStream( manifest_resource_name );
  266. // Decompress the embedded resource.
  267. using( GZipStream zip = new GZipStream( stream, CompressionMode.Decompress ) )
  268. {
  269. // Load this decompressed embedded resource into an XDocument using a TextReader.
  270. using( TextReader sr = new StreamReader( zip ) )
  271. {
  272. document = XDocument.Load( sr );
  273. }
  274. }
  275. // Return the decompressed Xml as an XDocument.
  276. return document;
  277. }
  278. /// <summary>
  279. /// If this document does not contain a /word/styles.xml add the default one generated by Microsoft Word.
  280. /// </summary>
  281. /// <param name="package"></param>
  282. /// <returns></returns>
  283. internal static XDocument AddDefaultStylesXml( Package package )
  284. {
  285. XDocument stylesDoc;
  286. // Create the main document part for this package
  287. var word_styles = package.CreatePart( new Uri( "/word/styles.xml", UriKind.Relative ), "application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml", CompressionOption.Maximum );
  288. stylesDoc = HelperFunctions.DecompressXMLResource( "Xceed.Words.NET.Resources.default_styles.xml.gz" );
  289. var lang = stylesDoc.Root.Element( XName.Get( "docDefaults", DocX.w.NamespaceName ) ).Element( XName.Get( "rPrDefault", DocX.w.NamespaceName ) ).Element( XName.Get( "rPr", DocX.w.NamespaceName ) ).Element( XName.Get( "lang", DocX.w.NamespaceName ) );
  290. lang.SetAttributeValue( XName.Get( "val", DocX.w.NamespaceName ), CultureInfo.CurrentCulture );
  291. // Save /word/styles.xml
  292. using( TextWriter tw = new StreamWriter( new PackagePartStream( word_styles.GetStream( FileMode.Create, FileAccess.Write ) ) ) )
  293. {
  294. stylesDoc.Save( tw, SaveOptions.None );
  295. }
  296. var mainDocumentPart = package.GetParts().Where
  297. (
  298. p => p.ContentType.Equals( DOCUMENT_DOCUMENTTYPE, StringComparison.CurrentCultureIgnoreCase ) ||
  299. p.ContentType.Equals( TEMPLATE_DOCUMENTTYPE, StringComparison.CurrentCultureIgnoreCase )
  300. ).Single();
  301. mainDocumentPart.CreateRelationship( word_styles.Uri, TargetMode.Internal, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" );
  302. return stylesDoc;
  303. }
  304. internal static XElement CreateEdit( EditType t, DateTime edit_time, object content )
  305. {
  306. if( t == EditType.del )
  307. {
  308. foreach( object o in ( IEnumerable<XElement> )content )
  309. {
  310. if( o is XElement )
  311. {
  312. XElement e = ( o as XElement );
  313. IEnumerable<XElement> ts = e.DescendantsAndSelf( XName.Get( "t", DocX.w.NamespaceName ) );
  314. for( int i = 0; i < ts.Count(); i++ )
  315. {
  316. XElement text = ts.ElementAt( i );
  317. text.ReplaceWith( new XElement( DocX.w + "delText", text.Attributes(), text.Value ) );
  318. }
  319. }
  320. }
  321. }
  322. return
  323. (
  324. new XElement( DocX.w + t.ToString(),
  325. new XAttribute( DocX.w + "id", 0 ),
  326. new XAttribute( DocX.w + "author", WindowsIdentity.GetCurrent().Name ),
  327. new XAttribute( DocX.w + "date", edit_time ),
  328. content )
  329. );
  330. }
  331. internal static XElement CreateTable( int rowCount, int columnCount )
  332. {
  333. if( ( rowCount <= 0 ) || ( columnCount <= 0 ) )
  334. {
  335. throw new ArgumentOutOfRangeException( "Row and Column count must be greater than 0." );
  336. }
  337. int[] columnWidths = new int[columnCount];
  338. for (int i = 0; i < columnCount; i++)
  339. {
  340. columnWidths[i] = 2310;
  341. }
  342. return CreateTable(rowCount, columnWidths);
  343. }
  344. internal static XElement CreateTable( int rowCount, int[] columnWidths )
  345. {
  346. var newTable = new XElement( XName.Get( "tbl", DocX.w.NamespaceName ),
  347. new XElement( XName.Get( "tblPr", DocX.w.NamespaceName ),
  348. new XElement( XName.Get( "tblStyle", DocX.w.NamespaceName ), new XAttribute( XName.Get( "val", DocX.w.NamespaceName ), "TableGrid" ) ),
  349. new XElement( XName.Get( "tblW", DocX.w.NamespaceName ), new XAttribute( XName.Get( "w", DocX.w.NamespaceName ), "5000" ), new XAttribute( XName.Get( "type", DocX.w.NamespaceName ), "auto" ) ),
  350. new XElement( XName.Get( "tblLook", DocX.w.NamespaceName ), new XAttribute( XName.Get( "val", DocX.w.NamespaceName ), "04A0" ) ) ) );
  351. for( int i = 0; i < rowCount; i++ )
  352. {
  353. var row = new XElement( XName.Get( "tr", DocX.w.NamespaceName ) );
  354. for( int j = 0; j < columnWidths.Length; j++ )
  355. {
  356. var cell = HelperFunctions.CreateTableCell();
  357. row.Add( cell );
  358. }
  359. newTable.Add( row );
  360. }
  361. return newTable;
  362. }
  363. /// <summary>
  364. /// Create and return a cell of a table
  365. /// </summary>
  366. internal static XElement CreateTableCell( double w = 2310 )
  367. {
  368. return new XElement( XName.Get( "tc", DocX.w.NamespaceName ),
  369. new XElement( XName.Get( "tcPr", DocX.w.NamespaceName ),
  370. new XElement( XName.Get( "tcW", DocX.w.NamespaceName ),
  371. new XAttribute( XName.Get( "w", DocX.w.NamespaceName ), w ),
  372. new XAttribute( XName.Get( "type", DocX.w.NamespaceName ), "dxa" ) ) ),
  373. new XElement( XName.Get( "p", DocX.w.NamespaceName ), new XElement( XName.Get( "pPr", DocX.w.NamespaceName ) ) ) );
  374. }
  375. internal static void RenumberIDs( DocX document )
  376. {
  377. IEnumerable<XAttribute> trackerIDs =
  378. ( from d in document._mainDoc.Descendants()
  379. where d.Name.LocalName == "ins" || d.Name.LocalName == "del"
  380. select d.Attribute( XName.Get( "id", "http://schemas.openxmlformats.org/wordprocessingml/2006/main" ) ) );
  381. for( int i = 0; i < trackerIDs.Count(); i++ )
  382. trackerIDs.ElementAt( i ).Value = i.ToString();
  383. }
  384. internal static Paragraph GetFirstParagraphEffectedByInsert( DocX document, int index )
  385. {
  386. // This document contains no Paragraphs and insertion is at index 0
  387. if( document._paragraphLookup.Keys.Count() == 0 && index == 0 )
  388. return null;
  389. foreach( int paragraphEndIndex in document._paragraphLookup.Keys )
  390. {
  391. if( paragraphEndIndex >= index )
  392. return document._paragraphLookup[ paragraphEndIndex ];
  393. }
  394. throw new ArgumentOutOfRangeException();
  395. }
  396. internal static List<XElement> FormatInput( string text, XElement rPr )
  397. {
  398. var newRuns = new List<XElement>();
  399. var tabRun = new XElement( DocX.w + "tab" );
  400. var breakRun = new XElement( DocX.w + "br" );
  401. var sb = new StringBuilder();
  402. if( string.IsNullOrEmpty( text ) )
  403. {
  404. return newRuns; //I dont wanna get an exception if text == null, so just return empy list
  405. }
  406. char lastCharacter = '\0';
  407. foreach( char c in text )
  408. {
  409. switch( c )
  410. {
  411. case '\t':
  412. if( sb.Length > 0 )
  413. {
  414. var t = new XElement( DocX.w + "t", sb.ToString() );
  415. Xceed.Words.NET.Text.PreserveSpace( t );
  416. newRuns.Add( new XElement( DocX.w + "r", rPr, t ) );
  417. sb = new StringBuilder();
  418. }
  419. newRuns.Add( new XElement( DocX.w + "r", rPr, tabRun ) );
  420. break;
  421. case '\n':
  422. if( lastCharacter == '\r' )
  423. break;
  424. if( sb.Length > 0 )
  425. {
  426. var t = new XElement( DocX.w + "t", sb.ToString() );
  427. Xceed.Words.NET.Text.PreserveSpace( t );
  428. newRuns.Add( new XElement( DocX.w + "r", rPr, t ) );
  429. sb = new StringBuilder();
  430. }
  431. newRuns.Add( new XElement( DocX.w + "r", rPr, breakRun ) );
  432. break;
  433. case '\r':
  434. if( sb.Length > 0 )
  435. {
  436. var t = new XElement( DocX.w + "t", sb.ToString() );
  437. Xceed.Words.NET.Text.PreserveSpace( t );
  438. newRuns.Add( new XElement( DocX.w + "r", rPr, t ) );
  439. sb = new StringBuilder();
  440. }
  441. newRuns.Add( new XElement( DocX.w + "r", rPr, breakRun ) );
  442. break;
  443. default:
  444. sb.Append( c );
  445. break;
  446. }
  447. lastCharacter = c;
  448. }
  449. if( sb.Length > 0 )
  450. {
  451. var t = new XElement( DocX.w + "t", sb.ToString() );
  452. Xceed.Words.NET.Text.PreserveSpace( t );
  453. newRuns.Add( new XElement( DocX.w + "r", rPr, t ) );
  454. }
  455. return newRuns;
  456. }
  457. internal static XElement[] SplitParagraph( Paragraph p, int index )
  458. {
  459. // In this case edit dosent really matter, you have a choice.
  460. Run r = p.GetFirstRunEffectedByEdit( index, EditType.ins );
  461. XElement[] split;
  462. XElement before, after;
  463. if( r.Xml.Parent.Name.LocalName == "ins" )
  464. {
  465. split = p.SplitEdit( r.Xml.Parent, index, EditType.ins );
  466. before = new XElement( p.Xml.Name, p.Xml.Attributes(), r.Xml.Parent.ElementsBeforeSelf(), split[ 0 ] );
  467. after = new XElement( p.Xml.Name, p.Xml.Attributes(), r.Xml.Parent.ElementsAfterSelf(), split[ 1 ] );
  468. }
  469. else if( r.Xml.Parent.Name.LocalName == "del" )
  470. {
  471. split = p.SplitEdit( r.Xml.Parent, index, EditType.del );
  472. before = new XElement( p.Xml.Name, p.Xml.Attributes(), r.Xml.Parent.ElementsBeforeSelf(), split[ 0 ] );
  473. after = new XElement( p.Xml.Name, p.Xml.Attributes(), r.Xml.Parent.ElementsAfterSelf(), split[ 1 ] );
  474. }
  475. else
  476. {
  477. split = Run.SplitRun( r, index );
  478. before = new XElement( p.Xml.Name, p.Xml.Attributes(), r.Xml.ElementsBeforeSelf(), split[ 0 ] );
  479. after = new XElement( p.Xml.Name, p.Xml.Attributes(), split[ 1 ], r.Xml.ElementsAfterSelf() );
  480. }
  481. if( before.Elements().Count() == 0 )
  482. before = null;
  483. if( after.Elements().Count() == 0 )
  484. after = null;
  485. return new XElement[] { before, after };
  486. }
  487. /// <!--
  488. /// Bug found and fixed by trnilse. To see the change,
  489. /// please compare this release to the previous release using TFS compare.
  490. /// -->
  491. internal static bool IsSameFile( Stream streamOne, Stream streamTwo )
  492. {
  493. int file1byte, file2byte;
  494. if( streamOne.Length != streamTwo.Length )
  495. {
  496. // Return false to indicate files are different
  497. return false;
  498. }
  499. // Read and compare a byte from each file until either a
  500. // non-matching set of bytes is found or until the end of
  501. // file1 is reached.
  502. do
  503. {
  504. // Read one byte from each file.
  505. file1byte = streamOne.ReadByte();
  506. file2byte = streamTwo.ReadByte();
  507. }
  508. while( ( file1byte == file2byte ) && ( file1byte != -1 ) );
  509. // Return the success of the comparison. "file1byte" is
  510. // equal to "file2byte" at this point only if the files are
  511. // the same.
  512. streamOne.Position = 0;
  513. streamTwo.Position = 0;
  514. return ( ( file1byte - file2byte ) == 0 );
  515. }
  516. /// <summary>
  517. /// Add the default numbering.xml if it is missing from this document
  518. /// </summary>
  519. internal static XDocument AddDefaultNumberingXml(Package package)
  520. {
  521. XDocument numberingDoc;
  522. var numberingPart = package.CreatePart(new Uri("/word/numbering.xml", UriKind.Relative), "application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml", CompressionOption.Maximum);
  523. numberingDoc = DecompressXMLResource("Xceed.Words.NET.Resources.numbering.xml.gz");
  524. using( TextWriter tw = new StreamWriter( new PackagePartStream( numberingPart.GetStream( FileMode.Create, FileAccess.Write ) ) ) )
  525. {
  526. numberingDoc.Save( tw, SaveOptions.None );
  527. }
  528. var mainDocPart = package.GetParts().Single( p => p.ContentType.Equals( DOCUMENT_DOCUMENTTYPE, StringComparison.CurrentCultureIgnoreCase ) ||
  529. p.ContentType.Equals( TEMPLATE_DOCUMENTTYPE, StringComparison.CurrentCultureIgnoreCase ) );
  530. mainDocPart.CreateRelationship(numberingPart.Uri, TargetMode.Internal, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering");
  531. return numberingDoc;
  532. }
  533. internal static List CreateItemInList(List list, string listText, int level = 0, ListItemType listType = ListItemType.Numbered, int? startNumber = null, bool trackChanges = false, bool continueNumbering = false)
  534. {
  535. if (list.NumId == 0)
  536. {
  537. list.CreateNewNumberingNumId(level, listType, startNumber, continueNumbering);
  538. }
  539. if (listText != null)
  540. {
  541. var newSection = new XElement
  542. (
  543. XName.Get("p", DocX.w.NamespaceName),
  544. new XElement(XName.Get("pPr", DocX.w.NamespaceName),
  545. new XElement(XName.Get("numPr", DocX.w.NamespaceName),
  546. new XElement(XName.Get("ilvl", DocX.w.NamespaceName), new XAttribute(DocX.w + "val", level)),
  547. new XElement(XName.Get("numId", DocX.w.NamespaceName), new XAttribute(DocX.w + "val", list.NumId)))),
  548. new XElement(XName.Get("r", DocX.w.NamespaceName), new XElement(XName.Get("t", DocX.w.NamespaceName), listText))
  549. );
  550. if (trackChanges)
  551. newSection = CreateEdit(EditType.ins, DateTime.Now, newSection);
  552. if (startNumber == null)
  553. list.AddItem(new Paragraph(list.Document, newSection, 0, ContainerType.Paragraph));
  554. else
  555. list.AddItemWithStartValue(new Paragraph(list.Document, newSection, 0, ContainerType.Paragraph), (int)startNumber);
  556. }
  557. return list;
  558. }
  559. internal static UnderlineStyle GetUnderlineStyle(string styleName)
  560. {
  561. switch (styleName)
  562. {
  563. case "single":
  564. return UnderlineStyle.singleLine;
  565. case "double":
  566. return UnderlineStyle.doubleLine;
  567. case "thick":
  568. return UnderlineStyle.thick;
  569. case "dotted":
  570. return UnderlineStyle.dotted;
  571. case "dottedHeavy":
  572. return UnderlineStyle.dottedHeavy;
  573. case "dash":
  574. return UnderlineStyle.dash;
  575. case "dashedHeavy":
  576. return UnderlineStyle.dashedHeavy;
  577. case "dashLong":
  578. return UnderlineStyle.dashLong;
  579. case "dashLongHeavy":
  580. return UnderlineStyle.dashLongHeavy;
  581. case "dotDash":
  582. return UnderlineStyle.dotDash;
  583. case "dashDotHeavy":
  584. return UnderlineStyle.dashDotHeavy;
  585. case "dotDotDash":
  586. return UnderlineStyle.dotDotDash;
  587. case "dashDotDotHeavy":
  588. return UnderlineStyle.dashDotDotHeavy;
  589. case "wave":
  590. return UnderlineStyle.wave;
  591. case "wavyHeavy":
  592. return UnderlineStyle.wavyHeavy;
  593. case "wavyDouble":
  594. return UnderlineStyle.wavyDouble;
  595. case "words":
  596. return UnderlineStyle.words;
  597. default:
  598. return UnderlineStyle.none;
  599. }
  600. }
  601. internal static bool ContainsEveryChildOf(XElement elementWanted, XElement elementToValidate, MatchFormattingOptions formattingOptions)
  602. {
  603. foreach (XElement subElement in elementWanted.Elements())
  604. {
  605. if (!elementToValidate.Elements(subElement.Name).Where(bElement => bElement.GetAttribute(XName.Get("val", DocX.w.NamespaceName)) == subElement.GetAttribute(XName.Get("val", DocX.w.NamespaceName))).Any())
  606. return false;
  607. }
  608. if (formattingOptions == MatchFormattingOptions.ExactMatch)
  609. return elementWanted.Elements().Count() == elementToValidate.Elements().Count();
  610. return true;
  611. }
  612. internal static string GetListItemType( Paragraph p, DocX document )
  613. {
  614. var ilvlNode = p.ParagraphNumberProperties.Descendants().FirstOrDefault( el => el.Name.LocalName == "ilvl" );
  615. var ilvlValue = ilvlNode.Attribute( DocX.w + "val" ).Value;
  616. var numIdNode = p.ParagraphNumberProperties.Descendants().FirstOrDefault( el => el.Name.LocalName == "numId" );
  617. var numIdValue = numIdNode.Attribute( DocX.w + "val" ).Value;
  618. //find num node in numbering
  619. var numNodes = document._numbering.Descendants().Where( n => n.Name.LocalName == "num" );
  620. XElement numNode = numNodes.FirstOrDefault( node => node.Attribute( DocX.w + "numId" ).Value.Equals( numIdValue ) );
  621. if( numNode != null )
  622. {
  623. //Get abstractNumId node and its value from numNode
  624. var abstractNumIdNode = numNode.Descendants().First( n => n.Name.LocalName == "abstractNumId" );
  625. var abstractNumNodeValue = abstractNumIdNode.Attribute( DocX.w + "val" ).Value;
  626. var abstractNumNodes = document._numbering.Descendants().Where( n => n.Name.LocalName == "abstractNum" );
  627. XElement abstractNumNode = abstractNumNodes.FirstOrDefault( node => node.Attribute( DocX.w + "abstractNumId" ).Value.Equals( abstractNumNodeValue ) );
  628. //Find lvl node
  629. var lvlNodes = abstractNumNode.Descendants().Where( n => n.Name.LocalName == "lvl" );
  630. XElement lvlNode = null;
  631. foreach( XElement node in lvlNodes )
  632. {
  633. if( node.Attribute( DocX.w + "ilvl" ).Value.Equals( ilvlValue ) )
  634. {
  635. lvlNode = node;
  636. break;
  637. }
  638. }
  639. var numFmtNode = lvlNode.Descendants().First( n => n.Name.LocalName == "numFmt" );
  640. return numFmtNode.Attribute( DocX.w + "val" ).Value;
  641. }
  642. return null;
  643. }
  644. }
  645. }