Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

DocX.cs 166KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553
  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.Xml.Linq;
  14. using System.Xml;
  15. using System.IO;
  16. using System.Text.RegularExpressions;
  17. using System.IO.Packaging;
  18. using System.Security.Cryptography;
  19. using System.Drawing;
  20. using System.Collections.ObjectModel;
  21. namespace Xceed.Words.NET
  22. {
  23. /// <summary>
  24. /// Represents a document.
  25. /// </summary>
  26. public class DocX : Container, IDisposable
  27. {
  28. #region Namespaces
  29. static internal XNamespace w = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
  30. static internal XNamespace rel = "http://schemas.openxmlformats.org/package/2006/relationships";
  31. static internal XNamespace r = "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
  32. static internal XNamespace m = "http://schemas.openxmlformats.org/officeDocument/2006/math";
  33. static internal XNamespace customPropertiesSchema = "http://schemas.openxmlformats.org/officeDocument/2006/custom-properties";
  34. static internal XNamespace customVTypesSchema = "http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes";
  35. static internal XNamespace wp = "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing";
  36. static internal XNamespace a = "http://schemas.openxmlformats.org/drawingml/2006/main";
  37. static internal XNamespace c = "http://schemas.openxmlformats.org/drawingml/2006/chart";
  38. internal static XNamespace n = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering";
  39. static internal XNamespace v = "urn:schemas-microsoft-com:vml";
  40. #endregion
  41. #region Private Members
  42. private Headers _headers;
  43. private Footers _footers;
  44. private float _pageSizeMultiplier = 20.0f;
  45. private readonly object nextFreeDocPrIdLock = new object();
  46. private long? nextFreeDocPrId;
  47. #endregion
  48. #region Internal Constants
  49. internal const string RelationshipImage = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image";
  50. internal const string ContentTypeApplicationRelationShipXml = "application/vnd.openxmlformats-package.relationships+xml";
  51. #endregion
  52. #region Internal Members
  53. // Get the word\settings.xml part
  54. internal PackagePart _settingsPart;
  55. internal PackagePart _endnotesPart;
  56. internal PackagePart _footnotesPart;
  57. internal PackagePart _stylesPart;
  58. internal PackagePart _stylesWithEffectsPart;
  59. internal PackagePart _numberingPart;
  60. internal PackagePart _fontTablePart;
  61. #region Internal variables defined foreach DocX object
  62. // Object representation of the .docx
  63. internal Package _package;
  64. // The mainDocument is loaded into a XDocument object for easy querying and editing
  65. internal XDocument _mainDoc;
  66. internal XDocument _settings;
  67. internal XDocument _endnotes;
  68. internal XDocument _footnotes;
  69. internal XDocument _styles;
  70. internal XDocument _stylesWithEffects;
  71. internal XDocument _numbering;
  72. internal XDocument _fontTable;
  73. // A lookup for the Paragraphs in this document.
  74. internal Dictionary<int, Paragraph> _paragraphLookup = new Dictionary<int, Paragraph>();
  75. // Every document is stored in a MemoryStream, all edits made to a document are done in memory.
  76. internal MemoryStream _memoryStream;
  77. // The filename that this document was loaded from
  78. internal string _filename;
  79. // The stream that this document was loaded from
  80. internal Stream _stream;
  81. #endregion
  82. #endregion
  83. #region Public Properties
  84. /// <summary>
  85. /// Top margin in points. 1pt = 1/72 of an inch. Word internally writes docx using units = 1/20th of a point.
  86. /// </summary>
  87. public float MarginTop
  88. {
  89. get
  90. {
  91. return getMarginAttribute( XName.Get( "top", w.NamespaceName ) );
  92. }
  93. set
  94. {
  95. setMarginAttribute( XName.Get( "top", w.NamespaceName ), value );
  96. }
  97. }
  98. /// <summary>
  99. /// Bottom margin in points. 1pt = 1/72 of an inch. Word internally writes docx using units = 1/20th of a point.
  100. /// </summary>
  101. public float MarginBottom
  102. {
  103. get
  104. {
  105. return getMarginAttribute( XName.Get( "bottom", w.NamespaceName ) );
  106. }
  107. set
  108. {
  109. setMarginAttribute( XName.Get( "bottom", w.NamespaceName ), value );
  110. }
  111. }
  112. /// <summary>
  113. /// Left margin in points. 1pt = 1/72 of an inch. Word internally writes docx using units = 1/20th of a point.
  114. /// </summary>
  115. public float MarginLeft
  116. {
  117. get
  118. {
  119. return getMarginAttribute( XName.Get( "left", w.NamespaceName ) );
  120. }
  121. set
  122. {
  123. setMarginAttribute( XName.Get( "left", w.NamespaceName ), value );
  124. }
  125. }
  126. /// <summary>
  127. /// Right margin in points. 1pt = 1/72 of an inch. Word internally writes docx using units = 1/20th of a point.
  128. /// </summary>
  129. public float MarginRight
  130. {
  131. get
  132. {
  133. return getMarginAttribute( XName.Get( "right", w.NamespaceName ) );
  134. }
  135. set
  136. {
  137. setMarginAttribute( XName.Get( "right", w.NamespaceName ), value );
  138. }
  139. }
  140. /// <summary>
  141. /// Header margin value in points. 1pt = 1/72 of an inch. Word internally writes docx using units = 1/20th of a point.
  142. /// </summary>
  143. public float MarginHeader
  144. {
  145. get
  146. {
  147. return getMarginAttribute(XName.Get("header", w.NamespaceName));
  148. }
  149. set
  150. {
  151. setMarginAttribute(XName.Get("header", w.NamespaceName), value);
  152. }
  153. }
  154. /// <summary>
  155. /// Footer margin value in points. 1pt = 1/72 of an inch. Word internally writes docx using units = 1/20th of a point.
  156. /// </summary>
  157. public float MarginFooter
  158. {
  159. get
  160. {
  161. return getMarginAttribute(XName.Get("footer", w.NamespaceName));
  162. }
  163. set
  164. {
  165. setMarginAttribute(XName.Get("footer", w.NamespaceName), value);
  166. }
  167. }
  168. public bool MirrorMargins
  169. {
  170. get
  171. {
  172. return getMirrorMargins(XName.Get("mirrorMargins", DocX.w.NamespaceName));
  173. }
  174. set
  175. {
  176. setMirrorMargins(XName.Get("mirrorMargins", DocX.w.NamespaceName), value);
  177. }
  178. }
  179. /// <summary>
  180. /// Page width in points. 1pt = 1/72 of an inch. Word internally writes docx using units = 1/20th of a point.
  181. /// </summary>
  182. public float PageWidth
  183. {
  184. get
  185. {
  186. var body = _mainDoc.Root.Element( XName.Get( "body", w.NamespaceName ) );
  187. var sectPr = body.Element( XName.Get( "sectPr", w.NamespaceName ) );
  188. var pgSz = sectPr?.Element( XName.Get( "pgSz", w.NamespaceName ) );
  189. if( pgSz != null )
  190. {
  191. var w = pgSz.Attribute( XName.Get( "w", DocX.w.NamespaceName ) );
  192. if( w != null )
  193. {
  194. float f;
  195. if( float.TryParse( w.Value, out f ) )
  196. return ( int )( f / _pageSizeMultiplier );
  197. }
  198. }
  199. return ( 12240.0f / _pageSizeMultiplier );
  200. }
  201. set
  202. {
  203. var body = _mainDoc.Root.Element( XName.Get( "body", w.NamespaceName ) );
  204. var sectPr = body.Element( XName.Get( "sectPr", w.NamespaceName ) );
  205. var pgSz = sectPr.Element( XName.Get( "pgSz", w.NamespaceName ) );
  206. pgSz?.SetAttributeValue( XName.Get( "w", w.NamespaceName ), value * Convert.ToInt32( _pageSizeMultiplier ) );
  207. }
  208. }
  209. /// <summary>
  210. /// Page height in points. 1pt = 1/72 of an inch. Word internally writes docx using units = 1/20th of a point.
  211. /// </summary>
  212. public float PageHeight
  213. {
  214. get
  215. {
  216. var body = _mainDoc.Root.Element( XName.Get( "body", w.NamespaceName ) );
  217. var sectPr = body.Element( XName.Get( "sectPr", w.NamespaceName ) );
  218. if( sectPr != null )
  219. {
  220. var pgSz = sectPr.Element( XName.Get( "pgSz", w.NamespaceName ) );
  221. if( pgSz != null )
  222. {
  223. var w = pgSz.Attribute( XName.Get( "h", DocX.w.NamespaceName ) );
  224. if( w != null )
  225. {
  226. float f;
  227. if( float.TryParse( w.Value, out f ) )
  228. return ( int )( f / _pageSizeMultiplier );
  229. }
  230. }
  231. }
  232. return ( 15840.0f / _pageSizeMultiplier );
  233. }
  234. set
  235. {
  236. var body = _mainDoc.Root.Element( XName.Get( "body", w.NamespaceName ) );
  237. if( body != null )
  238. {
  239. var sectPr = body.Element( XName.Get( "sectPr", w.NamespaceName ) );
  240. if( sectPr != null )
  241. {
  242. var pgSz = sectPr.Element( XName.Get( "pgSz", w.NamespaceName ) );
  243. if( pgSz != null )
  244. {
  245. pgSz.SetAttributeValue( XName.Get( "h", w.NamespaceName ), value * Convert.ToInt32( _pageSizeMultiplier ) );
  246. }
  247. }
  248. }
  249. }
  250. }
  251. /// <summary>
  252. /// Returns true if any editing restrictions are imposed on this document.
  253. /// </summary>
  254. /// <example>
  255. /// <code>
  256. /// // Create a new document.
  257. /// using (DocX document = DocX.Create(@"Test.docx"))
  258. /// {
  259. /// if(document.isProtected)
  260. /// Console.WriteLine("Protected");
  261. /// else
  262. /// Console.WriteLine("Not protected");
  263. ///
  264. /// // Save the document.
  265. /// document.Save();
  266. /// }
  267. /// </code>
  268. /// </example>
  269. /// <seealso cref="AddProtection(EditRestrictions)"/>
  270. /// <seealso cref="RemoveProtection"/>
  271. /// <seealso cref="GetProtectionType"/>
  272. public bool isProtected
  273. {
  274. get
  275. {
  276. return _settings.Descendants( XName.Get( "documentProtection", w.NamespaceName ) ).Count() > 0;
  277. }
  278. }
  279. public PageLayout PageLayout
  280. {
  281. get
  282. {
  283. XElement sectPr = Xml.Element( XName.Get( "sectPr", w.NamespaceName ) );
  284. if( sectPr == null )
  285. {
  286. Xml.SetElementValue( XName.Get( "sectPr", w.NamespaceName ), string.Empty );
  287. sectPr = Xml.Element( XName.Get( "sectPr", w.NamespaceName ) );
  288. }
  289. return new PageLayout( this, sectPr );
  290. }
  291. }
  292. /// <summary>
  293. /// Returns a collection of Headers in this Document.
  294. /// A document typically contains three Headers.
  295. /// A default one (odd), one for the first page and one for even pages.
  296. /// </summary>
  297. /// <example>
  298. /// <code>
  299. /// // Create a document.
  300. /// using (DocX document = DocX.Create(@"Test.docx"))
  301. /// {
  302. /// // Add header support to this document.
  303. /// document.AddHeaders();
  304. ///
  305. /// // Get a collection of all headers in this document.
  306. /// Headers headers = document.Headers;
  307. ///
  308. /// // The header used for the first page of this document.
  309. /// Header first = headers.first;
  310. ///
  311. /// // The header used for odd pages of this document.
  312. /// Header odd = headers.odd;
  313. ///
  314. /// // The header used for even pages of this document.
  315. /// Header even = headers.even;
  316. /// }
  317. /// </code>
  318. /// </example>
  319. public Headers Headers
  320. {
  321. get
  322. {
  323. return _headers;
  324. }
  325. }
  326. /// <summary>
  327. /// Returns a collection of Footers in this Document.
  328. /// A document typically contains three Footers.
  329. /// A default one (odd), one for the first page and one for even pages.
  330. /// </summary>
  331. /// <example>
  332. /// <code>
  333. /// // Create a document.
  334. /// using (DocX document = DocX.Create(@"Test.docx"))
  335. /// {
  336. /// // Add footer support to this document.
  337. /// document.AddFooters();
  338. ///
  339. /// // Get a collection of all footers in this document.
  340. /// Footers footers = document.Footers;
  341. ///
  342. /// // The footer used for the first page of this document.
  343. /// Footer first = footers.first;
  344. ///
  345. /// // The footer used for odd pages of this document.
  346. /// Footer odd = footers.odd;
  347. ///
  348. /// // The footer used for even pages of this document.
  349. /// Footer even = footers.even;
  350. /// }
  351. /// </code>
  352. /// </example>
  353. public Footers Footers
  354. {
  355. get
  356. {
  357. return _footers;
  358. }
  359. }
  360. /// <summary>
  361. /// Should the Document use different Headers and Footers for odd and even pages?
  362. /// </summary>
  363. /// <example>
  364. /// <code>
  365. /// // Create a document.
  366. /// using (DocX document = DocX.Create(@"Test.docx"))
  367. /// {
  368. /// // Add header support to this document.
  369. /// document.AddHeaders();
  370. ///
  371. /// // Get a collection of all headers in this document.
  372. /// Headers headers = document.Headers;
  373. ///
  374. /// // The header used for odd pages of this document.
  375. /// Header odd = headers.odd;
  376. ///
  377. /// // The header used for even pages of this document.
  378. /// Header even = headers.even;
  379. ///
  380. /// // Force the document to use a different header for odd and even pages.
  381. /// document.DifferentOddAndEvenPages = true;
  382. ///
  383. /// // Content can be added to the Headers in the same manor that it would be added to the main document.
  384. /// Paragraph p1 = odd.InsertParagraph();
  385. /// p1.Append("This is the odd pages header.");
  386. ///
  387. /// Paragraph p2 = even.InsertParagraph();
  388. /// p2.Append("This is the even pages header.");
  389. ///
  390. /// // Save all changes to this document.
  391. /// document.Save();
  392. /// }// Release this document from memory.
  393. /// </code>
  394. /// </example>
  395. public bool DifferentOddAndEvenPages
  396. {
  397. get
  398. {
  399. XDocument settings;
  400. using( TextReader tr = new StreamReader( _settingsPart.GetStream() ) )
  401. {
  402. settings = XDocument.Load( tr );
  403. }
  404. var evenAndOddHeaders = settings.Root.Element( w + "evenAndOddHeaders" );
  405. return ( evenAndOddHeaders != null );
  406. }
  407. set
  408. {
  409. XDocument settings;
  410. using( TextReader tr = new StreamReader( _settingsPart.GetStream() ) )
  411. {
  412. settings = XDocument.Load( tr );
  413. }
  414. var evenAndOddHeaders = settings.Root.Element( w + "evenAndOddHeaders" );
  415. if( evenAndOddHeaders == null )
  416. {
  417. if( value )
  418. {
  419. settings.Root.AddFirst( new XElement( w + "evenAndOddHeaders" ) );
  420. }
  421. }
  422. else
  423. {
  424. if( !value )
  425. {
  426. evenAndOddHeaders.Remove();
  427. }
  428. }
  429. using( TextWriter tw = new StreamWriter( new PackagePartStream( _settingsPart.GetStream() ) ) )
  430. {
  431. settings.Save( tw );
  432. }
  433. }
  434. }
  435. /// <summary>
  436. /// Should the Document use an independent Header and Footer for the first page?
  437. /// </summary>
  438. /// <example>
  439. /// // Create a document.
  440. /// using (DocX document = DocX.Create(@"Test.docx"))
  441. /// {
  442. /// // Add header support to this document.
  443. /// document.AddHeaders();
  444. ///
  445. /// // The header used for the first page of this document.
  446. /// Header first = document.Headers.first;
  447. ///
  448. /// // Force the document to use a different header for first page.
  449. /// document.DifferentFirstPage = true;
  450. ///
  451. /// // Content can be added to the Headers in the same manor that it would be added to the main document.
  452. /// Paragraph p = first.InsertParagraph();
  453. /// p.Append("This is the first pages header.");
  454. ///
  455. /// // Save all changes to this document.
  456. /// document.Save();
  457. /// }// Release this document from memory.
  458. /// </example>
  459. public bool DifferentFirstPage
  460. {
  461. get
  462. {
  463. var body = _mainDoc.Root.Element( w + "body" );
  464. var sectPr = body.Element( w + "sectPr" );
  465. var titlePg = sectPr?.Element( w + "titlePg" );
  466. return titlePg != null;
  467. }
  468. set
  469. {
  470. var body = _mainDoc.Root.Element( w + "body" );
  471. body.Add( new XElement( w + "sectPr", string.Empty ) );
  472. var sectPr = body.Element( w + "sectPr" );
  473. var titlePg = sectPr.Element( w + "titlePg" );
  474. if( titlePg == null )
  475. {
  476. if( value )
  477. {
  478. sectPr.Add( new XElement( w + "titlePg", string.Empty ) );
  479. }
  480. }
  481. else
  482. {
  483. if( !value )
  484. {
  485. titlePg.Remove();
  486. }
  487. }
  488. }
  489. }
  490. /// <summary>
  491. /// Returns a list of Images in this document.
  492. /// </summary>
  493. /// <example>
  494. /// Get the unique Id of every Image in this document.
  495. /// <code>
  496. /// // Load a document.
  497. /// DocX document = DocX.Load(@"C:\Example\Test.docx");
  498. ///
  499. /// // Loop through each Image in this document.
  500. /// foreach (Xceed.Words.NET.Image i in document.Images)
  501. /// {
  502. /// // Get the unique Id which identifies this Image.
  503. /// string uniqueId = i.Id;
  504. /// }
  505. ///
  506. /// </code>
  507. /// </example>
  508. /// <seealso cref="AddImage(string)"/>
  509. /// <seealso cref="AddImage(Stream, string)"/>
  510. /// <seealso cref="Paragraph.Pictures"/>
  511. /// <seealso cref="Paragraph.InsertPicture"/>
  512. public List<Image> Images
  513. {
  514. get
  515. {
  516. var imageRelationships = this.PackagePart.GetRelationshipsByType( RelationshipImage );
  517. if( imageRelationships.Any() )
  518. {
  519. return
  520. (
  521. from i in imageRelationships
  522. select new Image( this, i )
  523. ).ToList();
  524. }
  525. return new List<Image>();
  526. }
  527. }
  528. /// <summary>
  529. /// Returns a list of custom properties in this document.
  530. /// </summary>
  531. /// <example>
  532. /// Method 1: Get the name, type and value of each CustomProperty in this document.
  533. /// <code>
  534. /// // Load Example.docx
  535. /// DocX document = DocX.Load(@"C:\Example\Test.docx");
  536. ///
  537. /// /*
  538. /// * No two custom properties can have the same name,
  539. /// * so a Dictionary is the perfect data structure to store them in.
  540. /// * Each custom property can be accessed using its name.
  541. /// */
  542. /// foreach (string name in document.CustomProperties.Keys)
  543. /// {
  544. /// // Grab a custom property using its name.
  545. /// CustomProperty cp = document.CustomProperties[name];
  546. ///
  547. /// // Write this custom properties details to Console.
  548. /// Console.WriteLine(string.Format("Name: '{0}', Value: {1}", cp.Name, cp.Value));
  549. /// }
  550. ///
  551. /// Console.WriteLine("Press any key...");
  552. ///
  553. /// // Wait for the user to press a key before closing the Console.
  554. /// Console.ReadKey();
  555. /// </code>
  556. /// </example>
  557. /// <example>
  558. /// Method 2: Get the name, type and value of each CustomProperty in this document.
  559. /// <code>
  560. /// // Load Example.docx
  561. /// DocX document = DocX.Load(@"C:\Example\Test.docx");
  562. ///
  563. /// /*
  564. /// * No two custom properties can have the same name,
  565. /// * so a Dictionary is the perfect data structure to store them in.
  566. /// * The values of this Dictionary are CustomProperties.
  567. /// */
  568. /// foreach (CustomProperty cp in document.CustomProperties.Values)
  569. /// {
  570. /// // Write this custom properties details to Console.
  571. /// Console.WriteLine(string.Format("Name: '{0}', Value: {1}", cp.Name, cp.Value));
  572. /// }
  573. ///
  574. /// Console.WriteLine("Press any key...");
  575. ///
  576. /// // Wait for the user to press a key before closing the Console.
  577. /// Console.ReadKey();
  578. /// </code>
  579. /// </example>
  580. /// <seealso cref="AddCustomProperty"/>
  581. public Dictionary<string, CustomProperty> CustomProperties
  582. {
  583. get
  584. {
  585. if( _package.PartExists( new Uri( "/docProps/custom.xml", UriKind.Relative ) ) )
  586. {
  587. PackagePart docProps_custom = _package.GetPart( new Uri( "/docProps/custom.xml", UriKind.Relative ) );
  588. XDocument customPropDoc;
  589. using( TextReader tr = new StreamReader( docProps_custom.GetStream( FileMode.Open, FileAccess.Read ) ) )
  590. customPropDoc = XDocument.Load( tr, LoadOptions.PreserveWhitespace );
  591. // Get all of the custom properties in this document
  592. return
  593. (
  594. from p in customPropDoc.Descendants( XName.Get( "property", customPropertiesSchema.NamespaceName ) )
  595. let Name = p.Attribute( XName.Get( "name" ) ).Value
  596. let Type = p.Descendants().Single().Name.LocalName
  597. let Value = p.Descendants().Single().Value
  598. select new CustomProperty( Name, Type, Value )
  599. ).ToDictionary( p => p.Name, StringComparer.CurrentCultureIgnoreCase );
  600. }
  601. return new Dictionary<string, CustomProperty>();
  602. }
  603. }
  604. ///<summary>
  605. /// Returns the list of document core properties with corresponding values.
  606. ///</summary>
  607. public Dictionary<string, string> CoreProperties
  608. {
  609. get
  610. {
  611. if( _package.PartExists( new Uri( "/docProps/core.xml", UriKind.Relative ) ) )
  612. {
  613. PackagePart docProps_Core = _package.GetPart( new Uri( "/docProps/core.xml", UriKind.Relative ) );
  614. XDocument corePropDoc;
  615. using( TextReader tr = new StreamReader( docProps_Core.GetStream( FileMode.Open, FileAccess.Read ) ) )
  616. corePropDoc = XDocument.Load( tr, LoadOptions.PreserveWhitespace );
  617. // Get all of the core properties in this document
  618. return ( from docProperty in corePropDoc.Root.Elements()
  619. select
  620. new KeyValuePair<string, string>(
  621. string.Format(
  622. "{0}:{1}",
  623. corePropDoc.Root.GetPrefixOfNamespace( docProperty.Name.Namespace ),
  624. docProperty.Name.LocalName ),
  625. docProperty.Value ) ).ToDictionary( p => p.Key, v => v.Value );
  626. }
  627. return new Dictionary<string, string>();
  628. }
  629. }
  630. /// <summary>
  631. /// Get the Text of this document.
  632. /// </summary>
  633. /// <example>
  634. /// Write to Console the Text from this document.
  635. /// <code>
  636. /// // Load a document
  637. /// DocX document = DocX.Load(@"C:\Example\Test.docx");
  638. ///
  639. /// // Get the text of this document.
  640. /// string text = document.Text;
  641. ///
  642. /// // Write the text of this document to Console.
  643. /// Console.Write(text);
  644. ///
  645. /// // Wait for the user to press a key before closing the console window.
  646. /// Console.ReadKey();
  647. /// </code>
  648. /// </example>
  649. public string Text
  650. {
  651. get
  652. {
  653. return HelperFunctions.GetText( Xml );
  654. }
  655. }
  656. public override ReadOnlyCollection<Paragraph> Paragraphs
  657. {
  658. get
  659. {
  660. var paragraphs = base.Paragraphs;
  661. foreach( var paragraph in paragraphs )
  662. {
  663. paragraph.PackagePart = this.PackagePart;
  664. }
  665. return paragraphs;
  666. }
  667. }
  668. public override List<List> Lists
  669. {
  670. get
  671. {
  672. var l = base.Lists;
  673. l.ForEach( x => x.Items.ForEach( i => i.PackagePart = this.PackagePart ) );
  674. return l;
  675. }
  676. }
  677. public override List<Table> Tables
  678. {
  679. get
  680. {
  681. var l = base.Tables;
  682. l.ForEach( x => x.PackagePart = this.PackagePart );
  683. return l;
  684. }
  685. }
  686. /// <summary>
  687. /// Get the Footnotes of this document
  688. /// </summary>
  689. public IEnumerable<string> FootnotesText
  690. {
  691. get
  692. {
  693. foreach( var note in _footnotes.Root.Elements( w + "footnote" ) )
  694. yield return HelperFunctions.GetText( note );
  695. }
  696. }
  697. /// <summary>
  698. /// Get the Endnotes of this document
  699. /// </summary>
  700. public IEnumerable<string> EndnotesText
  701. {
  702. get
  703. {
  704. foreach( var note in _endnotes.Root.Elements( w + "endnote" ) )
  705. yield return HelperFunctions.GetText( note );
  706. }
  707. }
  708. public BookmarkCollection Bookmarks
  709. {
  710. get
  711. {
  712. var bookmarks = new BookmarkCollection();
  713. for( int i = 0; i < this.Paragraphs.Count; ++i )
  714. {
  715. bookmarks.AddRange( this.Paragraphs[ i ].GetBookmarks() );
  716. }
  717. return bookmarks;
  718. }
  719. }
  720. #endregion
  721. #region Public Methods
  722. /// <summary>
  723. /// Returns the type of editing protection imposed on this document.
  724. /// </summary>
  725. /// <returns>The type of editing protection imposed on this document.</returns>
  726. /// <example>
  727. /// <code>
  728. /// Create a new document.
  729. /// using (DocX document = DocX.Create(@"Test.docx"))
  730. /// {
  731. /// // Make sure the document is protected before checking the protection type.
  732. /// if (document.isProtected)
  733. /// {
  734. /// EditRestrictions protection = document.GetProtectionType();
  735. /// Console.WriteLine("Document is protected using " + protection.ToString());
  736. /// }
  737. ///
  738. /// else
  739. /// Console.WriteLine("Document is not protected.");
  740. ///
  741. /// // Save the document.
  742. /// document.Save();
  743. /// }
  744. /// </code>
  745. /// </example>
  746. /// <seealso cref="AddProtection"/>
  747. /// <seealso cref="RemoveProtection"/>
  748. /// <seealso cref="isProtected"/>
  749. public EditRestrictions GetProtectionType()
  750. {
  751. if( isProtected )
  752. {
  753. XElement documentProtection = _settings.Descendants( XName.Get( "documentProtection", w.NamespaceName ) ).FirstOrDefault();
  754. string edit_type = documentProtection.Attribute( XName.Get( "edit", w.NamespaceName ) ).Value;
  755. return ( EditRestrictions )Enum.Parse( typeof( EditRestrictions ), edit_type );
  756. }
  757. return EditRestrictions.none;
  758. }
  759. /// <summary>
  760. /// Add editing protection to this document.
  761. /// </summary>
  762. /// <param name="er">The type of protection to add to this document.</param>
  763. /// <example>
  764. /// <code>
  765. /// // Create a new document.
  766. /// using (DocX document = DocX.Create(@"Test.docx"))
  767. /// {
  768. /// // Allow no editing, only the adding of comment.
  769. /// document.AddProtection(EditRestrictions.comments);
  770. ///
  771. /// // Save the document.
  772. /// document.Save();
  773. /// }
  774. /// </code>
  775. /// </example>
  776. /// <seealso cref="RemoveProtection"/>
  777. /// <seealso cref="GetProtectionType"/>
  778. /// <seealso cref="isProtected"/>
  779. public void AddProtection( EditRestrictions er )
  780. {
  781. // Call remove protection before adding a new protection element.
  782. RemoveProtection();
  783. if( er == EditRestrictions.none )
  784. return;
  785. var documentProtection = new XElement( XName.Get( "documentProtection", w.NamespaceName ) );
  786. documentProtection.Add( new XAttribute( XName.Get( "edit", w.NamespaceName ), er.ToString() ) );
  787. documentProtection.Add( new XAttribute( XName.Get( "enforcement", w.NamespaceName ), "1" ) );
  788. _settings.Root.AddFirst( documentProtection );
  789. }
  790. /// <summary>
  791. /// Remove editing protection from this document.
  792. /// </summary>
  793. /// <example>
  794. /// <code>
  795. /// // Create a new document.
  796. /// using (DocX document = DocX.Create(@"Test.docx"))
  797. /// {
  798. /// // Remove any editing restrictions that are imposed on this document.
  799. /// document.RemoveProtection();
  800. ///
  801. /// // Save the document.
  802. /// document.Save();
  803. /// }
  804. /// </code>
  805. /// </example>
  806. /// <seealso cref="AddProtection(EditRestrictions)"/>
  807. /// <seealso cref="GetProtectionType"/>
  808. /// <seealso cref="isProtected"/>
  809. public void RemoveProtection()
  810. {
  811. // Remove every node of type documentProtection.
  812. _settings.Descendants( XName.Get( "documentProtection", w.NamespaceName ) ).Remove();
  813. }
  814. /// <summary>
  815. /// Insert the contents of another document at the end of this document.
  816. /// </summary>
  817. /// <param name="remote_document">The document to insert at the end of this document.</param>
  818. /// <param name="append">When true, document is added at the end. If False, document is added at the beginning.</param>
  819. /// <example>
  820. /// Create a new document and insert an old document into it.
  821. /// <code>
  822. /// // Create a new document.
  823. /// using (DocX newDocument = DocX.Create(@"NewDocument.docx"))
  824. /// {
  825. /// // Load an old document.
  826. /// using (DocX oldDocument = DocX.Load(@"OldDocument.docx"))
  827. /// {
  828. /// // Insert the old document into the new document.
  829. /// newDocument.InsertDocument(oldDocument);
  830. ///
  831. /// // Save the new document.
  832. /// newDocument.Save();
  833. /// }// Release the old document from memory.
  834. /// }// Release the new document from memory.
  835. /// </code>
  836. /// <remarks>
  837. /// If the document being inserted contains Images, CustomProperties and or custom styles, these will be correctly inserted into the new document. In the case of Images, new ID's are generated for the Images being inserted to avoid ID conflicts. CustomProperties with the same name will be ignored not replaced.
  838. /// </remarks>
  839. /// </example>
  840. public void InsertDocument( DocX remote_document, bool append = true )
  841. {
  842. // We don't want to effect the origional XDocument, so create a new one from the old one.
  843. var remote_mainDoc = new XDocument( remote_document._mainDoc );
  844. XDocument remote_footnotes = null;
  845. if( remote_document._footnotes != null )
  846. {
  847. remote_footnotes = new XDocument( remote_document._footnotes );
  848. }
  849. XDocument remote_endnotes = null;
  850. if( remote_document._endnotes != null )
  851. {
  852. remote_endnotes = new XDocument( remote_document._endnotes );
  853. }
  854. // Remove all header and footer references.
  855. remote_mainDoc.Descendants( XName.Get( "headerReference", w.NamespaceName ) ).Remove();
  856. remote_mainDoc.Descendants( XName.Get( "footerReference", w.NamespaceName ) ).Remove();
  857. // Get the body of the remote document.
  858. var remote_body = remote_mainDoc.Root.Element( XName.Get( "body", w.NamespaceName ) );
  859. // Every file that is missing from the local document will have to be copied, every file that already exists will have to be merged.
  860. var ppc = remote_document._package.GetParts();
  861. var ignoreContentTypes = new List<string>
  862. {
  863. "application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml",
  864. "application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml",
  865. "application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml",
  866. "application/vnd.openxmlformats-package.core-properties+xml",
  867. "application/vnd.openxmlformats-officedocument.extended-properties+xml",
  868. ContentTypeApplicationRelationShipXml
  869. };
  870. var imageContentTypes = new List<string>
  871. {
  872. "image/jpeg",
  873. "image/jpg",
  874. "image/png",
  875. "image/bmp",
  876. "image/gif",
  877. "image/tiff",
  878. "image/icon",
  879. "image/pcx",
  880. "image/emf",
  881. "image/wmf"
  882. };
  883. // Check if each PackagePart pp exists in this document.
  884. foreach( PackagePart remote_pp in ppc )
  885. {
  886. if( ignoreContentTypes.Contains( remote_pp.ContentType ) || imageContentTypes.Contains( remote_pp.ContentType ) )
  887. continue;
  888. // If this external PackagePart already exits then we must merge them.
  889. if( _package.PartExists( remote_pp.Uri ) )
  890. {
  891. var local_pp = _package.GetPart( remote_pp.Uri );
  892. switch( remote_pp.ContentType )
  893. {
  894. case "application/vnd.openxmlformats-officedocument.custom-properties+xml":
  895. merge_customs( remote_pp, local_pp, remote_mainDoc );
  896. break;
  897. // Merge footnotes/endnotes before merging styles, then set the remote_footnotes to the just updated footnotes
  898. case "application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml":
  899. remote_footnotes = _footnotes;
  900. break;
  901. case "application/vnd.openxmlformats-officedocument.wordprocessingml.endnotes+xml":
  902. remote_endnotes = _endnotes;
  903. break;
  904. case "application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml":
  905. merge_styles( remote_pp, local_pp, remote_mainDoc, remote_document, remote_footnotes, remote_endnotes );
  906. break;
  907. // Merges Styles after merging the footnotes, so the changes will be applied to the correct document/footnotes.
  908. case "application/vnd.ms-word.stylesWithEffects+xml":
  909. merge_styles( remote_pp, local_pp, remote_mainDoc, remote_document, remote_footnotes, remote_endnotes );
  910. break;
  911. case "application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml":
  912. merge_fonts( remote_pp, local_pp, remote_mainDoc, remote_document );
  913. break;
  914. case "application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml":
  915. merge_numbering( remote_pp, local_pp, remote_mainDoc, remote_document );
  916. break;
  917. }
  918. }
  919. // If this external PackagePart does not exits in the internal document then we can simply copy it.
  920. else
  921. {
  922. var packagePart = clonePackagePart( remote_pp );
  923. switch( remote_pp.ContentType )
  924. {
  925. case "application/vnd.openxmlformats-officedocument.wordprocessingml.endnotes+xml":
  926. _endnotesPart = packagePart;
  927. _endnotes = remote_endnotes;
  928. break;
  929. case "application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml":
  930. _footnotesPart = packagePart;
  931. _footnotes = remote_footnotes;
  932. break;
  933. case "application/vnd.openxmlformats-officedocument.custom-properties+xml":
  934. break;
  935. case "application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml":
  936. _stylesPart = packagePart;
  937. using( TextReader tr = new StreamReader( _stylesPart.GetStream() ) )
  938. _styles = XDocument.Load( tr );
  939. break;
  940. case "application/vnd.ms-word.stylesWithEffects+xml":
  941. _stylesWithEffectsPart = packagePart;
  942. using( TextReader tr = new StreamReader( _stylesWithEffectsPart.GetStream() ) )
  943. _stylesWithEffects = XDocument.Load( tr );
  944. break;
  945. case "application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml":
  946. _fontTablePart = packagePart;
  947. using( TextReader tr = new StreamReader( _fontTablePart.GetStream() ) )
  948. _fontTable = XDocument.Load( tr );
  949. break;
  950. case "application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml":
  951. _numberingPart = packagePart;
  952. using( TextReader tr = new StreamReader( _numberingPart.GetStream() ) )
  953. _numbering = XDocument.Load( tr );
  954. break;
  955. }
  956. clonePackageRelationship( remote_document, remote_pp, remote_mainDoc );
  957. }
  958. }
  959. foreach( var hyperlink_rel in remote_document.PackagePart.GetRelationshipsByType( "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink" ) )
  960. {
  961. var old_rel_Id = hyperlink_rel.Id;
  962. var new_rel_Id = this.PackagePart.CreateRelationship( hyperlink_rel.TargetUri, hyperlink_rel.TargetMode, hyperlink_rel.RelationshipType ).Id;
  963. var hyperlink_refs = remote_mainDoc.Descendants( XName.Get( "hyperlink", w.NamespaceName ) );
  964. foreach( var hyperlink_ref in hyperlink_refs )
  965. {
  966. var a0 = hyperlink_ref.Attribute( XName.Get( "id", r.NamespaceName ) );
  967. if( a0 != null && a0.Value == old_rel_Id )
  968. {
  969. a0.SetValue( new_rel_Id );
  970. }
  971. }
  972. }
  973. foreach( var oleObject_rel in remote_document.PackagePart.GetRelationshipsByType( "http://schemas.openxmlformats.org/officeDocument/2006/relationships/oleObject" ) )
  974. {
  975. var oldRelationshipID = oleObject_rel.Id;
  976. var newRelationshipID = this.PackagePart.CreateRelationship( oleObject_rel.TargetUri, oleObject_rel.TargetMode, oleObject_rel.RelationshipType ).Id;
  977. var references = remote_mainDoc.Descendants( XName.Get( "OLEObject", "urn:schemas-microsoft-com:office:office" ) );
  978. foreach( var reference in references )
  979. {
  980. var attribute = reference.Attribute( XName.Get( "id", r.NamespaceName ) );
  981. if( attribute != null && attribute.Value == oldRelationshipID )
  982. attribute.SetValue( newRelationshipID );
  983. }
  984. }
  985. foreach( PackagePart remote_pp in ppc )
  986. {
  987. if( imageContentTypes.Contains( remote_pp.ContentType ) )
  988. {
  989. merge_images( remote_pp, remote_document, remote_mainDoc, remote_pp.ContentType );
  990. }
  991. }
  992. int id = 0;
  993. var local_docPrs = _mainDoc.Root.Descendants( XName.Get( "docPr", wp.NamespaceName ) );
  994. foreach( var local_docPr in local_docPrs )
  995. {
  996. var a_id = local_docPr.Attribute( XName.Get( "id" ) );
  997. int a_id_value;
  998. if( a_id != null && int.TryParse( a_id.Value, out a_id_value ) )
  999. {
  1000. if( a_id_value > id )
  1001. {
  1002. id = a_id_value;
  1003. }
  1004. }
  1005. }
  1006. id++;
  1007. // docPr must be sequential
  1008. var docPrs = remote_body.Descendants( XName.Get( "docPr", wp.NamespaceName ) );
  1009. foreach( var docPr in docPrs )
  1010. {
  1011. docPr.SetAttributeValue( XName.Get( "id" ), id );
  1012. id++;
  1013. }
  1014. // Add the remote documents contents to this document.
  1015. var local_body = _mainDoc.Root.Element( XName.Get( "body", w.NamespaceName ) );
  1016. if( append )
  1017. {
  1018. local_body.Add( remote_body.Elements() );
  1019. }
  1020. else
  1021. {
  1022. local_body.AddFirst( remote_body.Elements() );
  1023. }
  1024. // Copy any missing root attributes to the local document.
  1025. foreach( XAttribute a in remote_mainDoc.Root.Attributes() )
  1026. {
  1027. if( _mainDoc.Root.Attribute( a.Name ) == null )
  1028. {
  1029. _mainDoc.Root.SetAttributeValue( a.Name, a.Value );
  1030. }
  1031. }
  1032. }
  1033. /// <summary>
  1034. /// Insert a new Table at the end of this document.
  1035. /// </summary>
  1036. /// <param name="columnCount">The number of columns to create.</param>
  1037. /// <param name="rowCount">The number of rows to create.</param>
  1038. /// <returns>A new Table.</returns>
  1039. /// <example>
  1040. /// Insert a new Table with 2 columns and 3 rows, at the end of a document.
  1041. /// <code>
  1042. /// // Create a document.
  1043. /// using (DocX document = DocX.Create(@"C:\Example\Test.docx"))
  1044. /// {
  1045. /// // Create a new Table with 2 columns and 3 rows.
  1046. /// Table newTable = document.InsertTable(2, 3);
  1047. ///
  1048. /// // Set the design of this Table.
  1049. /// newTable.Design = TableDesign.LightShadingAccent2;
  1050. ///
  1051. /// // Set the column names.
  1052. /// newTable.Rows[0].Cells[0].Paragraph.InsertText("Ice Cream", false);
  1053. /// newTable.Rows[0].Cells[1].Paragraph.InsertText("Price", false);
  1054. ///
  1055. /// // Fill row 1
  1056. /// newTable.Rows[1].Cells[0].Paragraph.InsertText("Chocolate", false);
  1057. /// newTable.Rows[1].Cells[1].Paragraph.InsertText("€3:50", false);
  1058. ///
  1059. /// // Fill row 2
  1060. /// newTable.Rows[2].Cells[0].Paragraph.InsertText("Vanilla", false);
  1061. /// newTable.Rows[2].Cells[1].Paragraph.InsertText("€3:00", false);
  1062. ///
  1063. /// // Save all changes made to document b.
  1064. /// document.Save();
  1065. /// }// Release this document from memory.
  1066. /// </code>
  1067. /// </example>
  1068. public new Table InsertTable( int rowCount, int columnCount )
  1069. {
  1070. if( rowCount < 1 || columnCount < 1 )
  1071. throw new ArgumentOutOfRangeException( "Row and Column count must be greater than zero." );
  1072. var t = base.InsertTable( rowCount, columnCount );
  1073. t.PackagePart = this.PackagePart;
  1074. return t;
  1075. }
  1076. public Table AddTable( int rowCount, int columnCount )
  1077. {
  1078. if( rowCount < 1 || columnCount < 1 )
  1079. throw new ArgumentOutOfRangeException( "Row and Column count must be greater than zero." );
  1080. var t = new Table( this, HelperFunctions.CreateTable( rowCount, columnCount ) );
  1081. t.PackagePart = this.PackagePart;
  1082. return t;
  1083. }
  1084. /// <summary>
  1085. /// Insert a Table into this document. The Table's source can be a completely different document.
  1086. /// </summary>
  1087. /// <param name="t">The Table to insert.</param>
  1088. /// <param name="index">The index to insert this Table at.</param>
  1089. /// <returns>The Table now associated with this document.</returns>
  1090. /// <example>
  1091. /// Extract a Table from document a and insert it into document b, at index 10.
  1092. /// <code>
  1093. /// // Place holder for a Table.
  1094. /// Table t;
  1095. ///
  1096. /// // Load document a.
  1097. /// using (DocX documentA = DocX.Load(@"C:\Example\a.docx"))
  1098. /// {
  1099. /// // Get the first Table from this document.
  1100. /// t = documentA.Tables[0];
  1101. /// }
  1102. ///
  1103. /// // Load document b.
  1104. /// using (DocX documentB = DocX.Load(@"C:\Example\b.docx"))
  1105. /// {
  1106. /// /*
  1107. /// * Insert the Table that was extracted from document a, into document b.
  1108. /// * This creates a new Table that is now associated with document b.
  1109. /// */
  1110. /// Table newTable = documentB.InsertTable(10, t);
  1111. ///
  1112. /// // Save all changes made to document b.
  1113. /// documentB.Save();
  1114. /// }// Release this document from memory.
  1115. /// </code>
  1116. /// </example>
  1117. public new Table InsertTable( int index, Table t )
  1118. {
  1119. var t2 = base.InsertTable( index, t );
  1120. t2.PackagePart = this.PackagePart;
  1121. return t2;
  1122. }
  1123. /// <summary>
  1124. /// Insert a Table into this document. The Table's source can be a completely different document.
  1125. /// </summary>
  1126. /// <param name="t">The Table to insert.</param>
  1127. /// <returns>The Table now associated with this document.</returns>
  1128. /// <example>
  1129. /// Extract a Table from document a and insert it at the end of document b.
  1130. /// <code>
  1131. /// // Place holder for a Table.
  1132. /// Table t;
  1133. ///
  1134. /// // Load document a.
  1135. /// using (DocX documentA = DocX.Load(@"C:\Example\a.docx"))
  1136. /// {
  1137. /// // Get the first Table from this document.
  1138. /// t = documentA.Tables[0];
  1139. /// }
  1140. ///
  1141. /// // Load document b.
  1142. /// using (DocX documentB = DocX.Load(@"C:\Example\b.docx"))
  1143. /// {
  1144. /// /*
  1145. /// * Insert the Table that was extracted from document a, into document b.
  1146. /// * This creates a new Table that is now associated with document b.
  1147. /// */
  1148. /// Table newTable = documentB.InsertTable(t);
  1149. ///
  1150. /// // Save all changes made to document b.
  1151. /// documentB.Save();
  1152. /// }// Release this document from memory.
  1153. /// </code>
  1154. /// </example>
  1155. public new Table InsertTable( Table t )
  1156. {
  1157. t = base.InsertTable( t );
  1158. t.PackagePart = this.PackagePart;
  1159. return t;
  1160. }
  1161. /// <summary>
  1162. /// Insert a new Table at the end of this document.
  1163. /// </summary>
  1164. /// <param name="columnCount">The number of columns to create.</param>
  1165. /// <param name="rowCount">The number of rows to create.</param>
  1166. /// <param name="index">The index to insert this Table at.</param>
  1167. /// <returns>A new Table.</returns>
  1168. /// <example>
  1169. /// Insert a new Table with 2 columns and 3 rows, at index 37 in this document.
  1170. /// <code>
  1171. /// // Create a document.
  1172. /// using (DocX document = DocX.Load(@"C:\Example\Test.docx"))
  1173. /// {
  1174. /// // Create a new Table with 3 rows and 2 columns. Insert this Table at index 37.
  1175. /// Table newTable = document.InsertTable(37, 3, 2);
  1176. ///
  1177. /// // Set the design of this Table.
  1178. /// newTable.Design = TableDesign.LightShadingAccent3;
  1179. ///
  1180. /// // Set the column names.
  1181. /// newTable.Rows[0].Cells[0].Paragraph.InsertText("Ice Cream", false);
  1182. /// newTable.Rows[0].Cells[1].Paragraph.InsertText("Price", false);
  1183. ///
  1184. /// // Fill row 1
  1185. /// newTable.Rows[1].Cells[0].Paragraph.InsertText("Chocolate", false);
  1186. /// newTable.Rows[1].Cells[1].Paragraph.InsertText("€3:50", false);
  1187. ///
  1188. /// // Fill row 2
  1189. /// newTable.Rows[2].Cells[0].Paragraph.InsertText("Vanilla", false);
  1190. /// newTable.Rows[2].Cells[1].Paragraph.InsertText("€3:00", false);
  1191. ///
  1192. /// // Save all changes made to document b.
  1193. /// document.Save();
  1194. /// }// Release this document from memory.
  1195. /// </code>
  1196. /// </example>
  1197. public new Table InsertTable( int index, int rowCount, int columnCount )
  1198. {
  1199. if( rowCount < 1 || columnCount < 1 )
  1200. throw new ArgumentOutOfRangeException( "Row and Column count must be greater than zero." );
  1201. var t = base.InsertTable( index, rowCount, columnCount );
  1202. t.PackagePart = this.PackagePart;
  1203. return t;
  1204. }
  1205. /// <summary>
  1206. /// Creates a document using a Stream.
  1207. /// </summary>
  1208. /// <param name="stream">The Stream to create the document from.</param>
  1209. /// <param name="documentType"></param>
  1210. /// <returns>Returns a DocX object which represents the document.</returns>
  1211. /// <example>
  1212. /// Creating a document from a FileStream.
  1213. /// <code>
  1214. /// // Use a FileStream fs to create a new document.
  1215. /// using(FileStream fs = new FileStream(@"C:\Example\Test.docx", FileMode.Create))
  1216. /// {
  1217. /// // Load the document using fs
  1218. /// using (DocX document = DocX.Create(fs))
  1219. /// {
  1220. /// // Do something with the document here.
  1221. ///
  1222. /// // Save all changes made to this document.
  1223. /// document.Save();
  1224. /// }// Release this document from memory.
  1225. /// }
  1226. /// </code>
  1227. /// </example>
  1228. /// <example>
  1229. /// Creating a document in a SharePoint site.
  1230. /// <code>
  1231. /// using(SPSite mySite = new SPSite("http://server/sites/site"))
  1232. /// {
  1233. /// // Open a connection to the SharePoint site
  1234. /// using(SPWeb myWeb = mySite.OpenWeb())
  1235. /// {
  1236. /// // Create a MemoryStream ms.
  1237. /// using (MemoryStream ms = new MemoryStream())
  1238. /// {
  1239. /// // Create a document using ms.
  1240. /// using (DocX document = DocX.Create(ms))
  1241. /// {
  1242. /// // Do something with the document here.
  1243. ///
  1244. /// // Save all changes made to this document.
  1245. /// document.Save();
  1246. /// }// Release this document from memory
  1247. ///
  1248. /// // Add the document to the SharePoint site
  1249. /// web.Files.Add("filename", ms.ToArray(), true);
  1250. /// }
  1251. /// }
  1252. /// }
  1253. /// </code>
  1254. /// </example>
  1255. /// <seealso cref="DocX.Load(System.IO.Stream)"/>
  1256. /// <seealso cref="DocX.Load(string)"/>
  1257. /// <seealso cref="DocX.Save()"/>
  1258. public static DocX Create( Stream stream, DocumentTypes documentType = DocumentTypes.Document )
  1259. {
  1260. var document = CreateDocument( documentType );
  1261. document._stream = stream;
  1262. return document;
  1263. }
  1264. /// <summary>
  1265. /// Creates a document using a fully qualified or relative filename.
  1266. /// </summary>
  1267. /// <param name="filename">The fully qualified or relative filename.</param>
  1268. /// <param name="documentType"></param>
  1269. /// <returns>Returns a DocX object which represents the document.</returns>
  1270. /// <example>
  1271. /// <code>
  1272. /// // Create a document using a relative filename.
  1273. /// using (DocX document = DocX.Create(@"..\Test.docx"))
  1274. /// {
  1275. /// // Do something with the document here.
  1276. ///
  1277. /// // Save all changes made to this document.
  1278. /// document.Save();
  1279. /// }// Release this document from memory
  1280. /// </code>
  1281. /// <code>
  1282. /// // Create a document using a relative filename.
  1283. /// using (DocX document = DocX.Create(@"..\Test.docx"))
  1284. /// {
  1285. /// // Do something with the document here.
  1286. ///
  1287. /// // Save all changes made to this document.
  1288. /// document.Save();
  1289. /// }// Release this document from memory
  1290. /// </code>
  1291. /// <seealso cref="DocX.Load(System.IO.Stream)"/>
  1292. /// <seealso cref="DocX.Load(string)"/>
  1293. /// <seealso cref="DocX.Save()"/>
  1294. /// </example>
  1295. public static DocX Create( string filename, DocumentTypes documentType = DocumentTypes.Document )
  1296. {
  1297. var document = CreateDocument( documentType );
  1298. document._filename = filename;
  1299. return document;
  1300. }
  1301. /// <summary>
  1302. /// Loads a document into a DocX object using a Stream.
  1303. /// </summary>
  1304. /// <param name="stream">The Stream to load the document from.</param>
  1305. /// <returns>
  1306. /// Returns a DocX object which represents the document.
  1307. /// </returns>
  1308. /// <example>
  1309. /// Loading a document from a FileStream.
  1310. /// <code>
  1311. /// // Open a FileStream fs to a document.
  1312. /// using (FileStream fs = new FileStream(@"C:\Example\Test.docx", FileMode.Open))
  1313. /// {
  1314. /// // Load the document using fs.
  1315. /// using (DocX document = DocX.Load(fs))
  1316. /// {
  1317. /// // Do something with the document here.
  1318. ///
  1319. /// // Save all changes made to the document.
  1320. /// document.Save();
  1321. /// }// Release this document from memory.
  1322. /// }
  1323. /// </code>
  1324. /// </example>
  1325. /// <example>
  1326. /// Loading a document from a SharePoint site.
  1327. /// <code>
  1328. /// // Get the SharePoint site that you want to access.
  1329. /// using (SPSite mySite = new SPSite("http://server/sites/site"))
  1330. /// {
  1331. /// // Open a connection to the SharePoint site
  1332. /// using (SPWeb myWeb = mySite.OpenWeb())
  1333. /// {
  1334. /// // Grab a document stored on this site.
  1335. /// SPFile file = web.GetFile("Source_Folder_Name/Source_File");
  1336. ///
  1337. /// // DocX.Load requires a Stream, so open a Stream to this document.
  1338. /// Stream str = new MemoryStream(file.OpenBinary());
  1339. ///
  1340. /// // Load the file using the Stream str.
  1341. /// using (DocX document = DocX.Load(str))
  1342. /// {
  1343. /// // Do something with the document here.
  1344. ///
  1345. /// // Save all changes made to the document.
  1346. /// document.Save();
  1347. /// }// Release this document from memory.
  1348. /// }
  1349. /// }
  1350. /// </code>
  1351. /// </example>
  1352. /// <seealso cref="DocX.Load(string)"/>
  1353. /// <seealso cref="DocX.Save()"/>
  1354. public static DocX Load( Stream stream )
  1355. {
  1356. var ms = new MemoryStream();
  1357. stream.Position = 0;
  1358. var data = new byte[ stream.Length ];
  1359. stream.Read( data, 0, ( int )stream.Length );
  1360. ms.Write( data, 0, ( int )stream.Length );
  1361. // Open the docx package
  1362. var package = Package.Open( ms, FileMode.Open, FileAccess.ReadWrite );
  1363. var document = DocX.PostLoad( ref package );
  1364. document._package = package;
  1365. document._memoryStream = ms;
  1366. document._stream = stream;
  1367. return document;
  1368. }
  1369. /// <summary>
  1370. /// Loads a document into a DocX object using a fully qualified or relative filename.
  1371. /// </summary>
  1372. /// <param name="filename">The fully qualified or relative filename.</param>
  1373. /// <returns>
  1374. /// Returns a DocX object which represents the document.
  1375. /// </returns>
  1376. /// <example>
  1377. /// <code>
  1378. /// // Load a document using its fully qualified filename
  1379. /// using (DocX document = DocX.Load(@"C:\Example\Test.docx"))
  1380. /// {
  1381. /// // Do something with the document here
  1382. ///
  1383. /// // Save all changes made to document.
  1384. /// document.Save();
  1385. /// }// Release this document from memory.
  1386. /// </code>
  1387. /// <code>
  1388. /// // Load a document using its relative filename.
  1389. /// using(DocX document = DocX.Load(@"..\..\Test.docx"))
  1390. /// {
  1391. /// // Do something with the document here.
  1392. ///
  1393. /// // Save all changes made to document.
  1394. /// document.Save();
  1395. /// }// Release this document from memory.
  1396. /// </code>
  1397. /// <seealso cref="DocX.Load(System.IO.Stream)"/>
  1398. /// <seealso cref="DocX.Save()"/>
  1399. /// </example>
  1400. public static DocX Load( string filename )
  1401. {
  1402. if( !File.Exists( filename ) )
  1403. throw new FileNotFoundException( string.Format( "File could not be found {0}", filename ) );
  1404. var ms = new MemoryStream();
  1405. using( FileStream fs = new FileStream( filename, FileMode.Open, FileAccess.Read, FileShare.Read ) )
  1406. {
  1407. CopyStream( fs, ms );
  1408. }
  1409. // Open the docx package
  1410. var package = Package.Open( ms, FileMode.Open, FileAccess.ReadWrite );
  1411. var document = PostLoad( ref package );
  1412. document._package = package;
  1413. document._filename = filename;
  1414. document._memoryStream = ms;
  1415. return document;
  1416. }
  1417. ///<summary>
  1418. /// Applies document template to the document. Document template may include styles, headers, footers, properties, etc. as well as text content.
  1419. ///</summary>
  1420. ///<param name="templateFilePath">The path to the document template file.</param>
  1421. ///<exception cref="FileNotFoundException">The document template file not found.</exception>
  1422. public void ApplyTemplate( string templateFilePath )
  1423. {
  1424. ApplyTemplate( templateFilePath, true );
  1425. }
  1426. ///<summary>
  1427. /// Applies document template to the document. Document template may include styles, headers, footers, properties, etc. as well as text content.
  1428. ///</summary>
  1429. ///<param name="templateFilePath">The path to the document template file.</param>
  1430. ///<param name="includeContent">Whether to copy the document template text content to document.</param>
  1431. ///<exception cref="FileNotFoundException">The document template file not found.</exception>
  1432. public void ApplyTemplate( string templateFilePath, bool includeContent )
  1433. {
  1434. if( !File.Exists( templateFilePath ) )
  1435. {
  1436. throw new FileNotFoundException( string.Format( "File could not be found {0}", templateFilePath ) );
  1437. }
  1438. using( FileStream packageStream = new FileStream( templateFilePath, FileMode.Open, FileAccess.Read ) )
  1439. {
  1440. ApplyTemplate( packageStream, includeContent );
  1441. }
  1442. }
  1443. ///<summary>
  1444. /// Applies document template to the document. Document template may include styles, headers, footers, properties, etc. as well as text content.
  1445. ///</summary>
  1446. ///<param name="templateStream">The stream of the document template file.</param>
  1447. public void ApplyTemplate( Stream templateStream )
  1448. {
  1449. ApplyTemplate( templateStream, true );
  1450. }
  1451. ///<summary>
  1452. /// Applies document template to the document. Document template may include styles, headers, footers, properties, etc. as well as text content.
  1453. ///</summary>
  1454. ///<param name="templateStream">The stream of the document template file.</param>
  1455. ///<param name="includeContent">Whether to copy the document template text content to document.</param>
  1456. public void ApplyTemplate( Stream templateStream, bool includeContent )
  1457. {
  1458. var templatePackage = Package.Open( templateStream );
  1459. try
  1460. {
  1461. PackagePart documentPart = null;
  1462. XDocument documentDoc = null;
  1463. foreach( PackagePart packagePart in templatePackage.GetParts() )
  1464. {
  1465. switch( packagePart.Uri.ToString() )
  1466. {
  1467. case "/word/document.xml":
  1468. documentPart = packagePart;
  1469. using( XmlReader xr = XmlReader.Create( packagePart.GetStream( FileMode.Open, FileAccess.Read ) ) )
  1470. {
  1471. documentDoc = XDocument.Load( xr );
  1472. }
  1473. break;
  1474. case "/_rels/.rels":
  1475. if( !_package.PartExists( packagePart.Uri ) )
  1476. {
  1477. _package.CreatePart( packagePart.Uri, packagePart.ContentType, packagePart.CompressionOption );
  1478. }
  1479. var globalRelsPart = _package.GetPart( packagePart.Uri );
  1480. using(
  1481. var tr = new StreamReader(
  1482. packagePart.GetStream( FileMode.Open, FileAccess.Read ), Encoding.UTF8 ) )
  1483. {
  1484. using(
  1485. var tw = new StreamWriter(
  1486. new PackagePartStream( globalRelsPart.GetStream( FileMode.Create, FileAccess.Write ) ), Encoding.UTF8 ) )
  1487. {
  1488. tw.Write( tr.ReadToEnd() );
  1489. }
  1490. }
  1491. break;
  1492. case "/word/_rels/document.xml.rels":
  1493. break;
  1494. default:
  1495. if( !_package.PartExists( packagePart.Uri ) )
  1496. {
  1497. _package.CreatePart( packagePart.Uri, packagePart.ContentType, packagePart.CompressionOption );
  1498. }
  1499. var packagePartEncoding = Encoding.Default;
  1500. if( packagePart.Uri.ToString().EndsWith( ".xml" ) || packagePart.Uri.ToString().EndsWith( ".rels" ) )
  1501. {
  1502. packagePartEncoding = Encoding.UTF8;
  1503. }
  1504. var nativePart = _package.GetPart( packagePart.Uri );
  1505. using(
  1506. var tr = new StreamReader(
  1507. packagePart.GetStream( FileMode.Open, FileAccess.Read ), packagePartEncoding ) )
  1508. {
  1509. using(
  1510. var tw = new StreamWriter(
  1511. new PackagePartStream( nativePart.GetStream( FileMode.Create, FileAccess.Write ) ), tr.CurrentEncoding ) )
  1512. {
  1513. tw.Write( tr.ReadToEnd() );
  1514. }
  1515. }
  1516. break;
  1517. }
  1518. }
  1519. if( documentPart != null )
  1520. {
  1521. string mainContentType = documentPart.ContentType.Replace( "template.main", "document.main" );
  1522. if( _package.PartExists( documentPart.Uri ) )
  1523. {
  1524. _package.DeletePart( documentPart.Uri );
  1525. }
  1526. var documentNewPart = _package.CreatePart(
  1527. documentPart.Uri, mainContentType, documentPart.CompressionOption );
  1528. using( XmlWriter xw = XmlWriter.Create( new PackagePartStream( documentNewPart.GetStream( FileMode.Create, FileAccess.Write ) ) ) )
  1529. {
  1530. documentDoc.WriteTo( xw );
  1531. }
  1532. foreach( PackageRelationship documentPartRel in documentPart.GetRelationships() )
  1533. {
  1534. documentNewPart.CreateRelationship(
  1535. documentPartRel.TargetUri,
  1536. documentPartRel.TargetMode,
  1537. documentPartRel.RelationshipType,
  1538. documentPartRel.Id );
  1539. }
  1540. this.PackagePart = documentNewPart;
  1541. _mainDoc = documentDoc;
  1542. PopulateDocument( this, templatePackage );
  1543. // DragonFire: I added next line and recovered ApplyTemplate method.
  1544. // I do it, becouse PopulateDocument(...) writes into field "settingsPart" the part of Template's package
  1545. // and after line "templatePackage.Close();" in finally, field "settingsPart" becomes not available and method "Save" throw an exception...
  1546. // That's why I recreated settingsParts and unlinked it from Template's package =)
  1547. _settingsPart = HelperFunctions.CreateOrGetSettingsPart( _package );
  1548. }
  1549. if( !includeContent )
  1550. {
  1551. foreach( Paragraph paragraph in this.Paragraphs )
  1552. {
  1553. paragraph.Remove( false );
  1554. }
  1555. }
  1556. }
  1557. finally
  1558. {
  1559. _package.Flush();
  1560. var documentRelsPart = _package.GetPart( new Uri( "/word/_rels/document.xml.rels", UriKind.Relative ) );
  1561. using( TextReader tr = new StreamReader( documentRelsPart.GetStream( FileMode.Open, FileAccess.Read ) ) )
  1562. {
  1563. tr.Read();
  1564. }
  1565. templatePackage.Close();
  1566. PopulateDocument( Document, _package );
  1567. }
  1568. }
  1569. /// <summary>
  1570. /// Add an Image into this document from a fully qualified or relative filename.
  1571. /// </summary>
  1572. /// <param name="filename">The fully qualified or relative filename.</param>
  1573. /// <param name="contentType">MIME type of image, guessed if not given.</param>
  1574. /// <returns>An Image file.</returns>
  1575. /// <example>
  1576. /// Add an Image into this document from a fully qualified filename.
  1577. /// <code>
  1578. /// // Load a document.
  1579. /// using (DocX document = DocX.Load(@"C:\Example\Test.docx"))
  1580. /// {
  1581. /// // Add an Image from a file.
  1582. /// document.AddImage(@"C:\Example\Image.png");
  1583. ///
  1584. /// // Save all changes made to this document.
  1585. /// document.Save();
  1586. /// }// Release this document from memory.
  1587. /// </code>
  1588. /// </example>
  1589. /// <seealso cref="AddImage(Stream, string)"/>
  1590. /// <seealso cref="Paragraph.InsertPicture"/>
  1591. public Image AddImage( string filename )
  1592. {
  1593. string contentType = "";
  1594. // The extension this file has will be taken to be its format.
  1595. switch( Path.GetExtension( filename ) )
  1596. {
  1597. case ".tiff":
  1598. contentType = "image/tif";
  1599. break;
  1600. case ".tif":
  1601. contentType = "image/tif";
  1602. break;
  1603. case ".png":
  1604. contentType = "image/png";
  1605. break;
  1606. case ".bmp":
  1607. contentType = "image/png";
  1608. break;
  1609. case ".gif":
  1610. contentType = "image/gif";
  1611. break;
  1612. case ".jpg":
  1613. contentType = "image/jpg";
  1614. break;
  1615. case ".jpeg":
  1616. contentType = "image/jpeg";
  1617. break;
  1618. default:
  1619. contentType = "image/jpg";
  1620. break;
  1621. }
  1622. return AddImage( filename as object, contentType );
  1623. }
  1624. /// <summary>
  1625. /// Add an Image into this document from a Stream.
  1626. /// </summary>
  1627. /// <param name="stream">A Stream stream.</param>
  1628. /// <param name="contentType">MIME type of image.</param>
  1629. /// <returns>An Image file.</returns>
  1630. /// <example>
  1631. /// Add an Image into a document using a Stream.
  1632. /// <code>
  1633. /// // Open a FileStream fs to an Image.
  1634. /// using (FileStream fs = new FileStream(@"C:\Example\Image.jpg", FileMode.Open))
  1635. /// {
  1636. /// // Load a document.
  1637. /// using (DocX document = DocX.Load(@"C:\Example\Test.docx"))
  1638. /// {
  1639. /// // Add an Image from a filestream fs.
  1640. /// document.AddImage(fs);
  1641. ///
  1642. /// // Save all changes made to this document.
  1643. /// document.Save();
  1644. /// }// Release this document from memory.
  1645. /// }
  1646. /// </code>
  1647. /// </example>
  1648. /// <seealso cref="AddImage(string)"/>
  1649. /// <seealso cref="Paragraph.InsertPicture"/>
  1650. public Image AddImage( Stream stream, string contentType = "image/jpeg" )
  1651. {
  1652. return AddImage( stream as object, contentType );
  1653. }
  1654. /// <summary>
  1655. /// Adds a hyperlink with a uri to a document and creates a Paragraph which uses it.
  1656. /// </summary>
  1657. /// <param name="text">The text as displayed by the hyperlink.</param>
  1658. /// <param name="uri">The hyperlink itself.</param>
  1659. /// <returns>Returns a hyperlink with a uri that can be inserted into a Paragraph.</returns>
  1660. /// <example>
  1661. /// Adds a hyperlink to a document and creates a Paragraph which uses it.
  1662. /// <code>
  1663. /// // Create a document.
  1664. /// using (DocX document = DocX.Create(@"Test.docx"))
  1665. /// {
  1666. /// // Add a hyperlink to this document.
  1667. /// Hyperlink h = document.AddHyperlink("Google", new Uri("http://www.google.com"));
  1668. ///
  1669. /// // Add a new Paragraph to this document.
  1670. /// Paragraph p = document.InsertParagraph();
  1671. /// p.Append("My favourite search engine is ");
  1672. /// p.AppendHyperlink(h);
  1673. /// p.Append(", I think it's great.");
  1674. ///
  1675. /// // Save all changes made to this document.
  1676. /// document.Save();
  1677. /// }
  1678. /// </code>
  1679. /// </example>
  1680. public Hyperlink AddHyperlink( string text, Uri uri )
  1681. {
  1682. return this.AddHyperlink( text, uri, null );
  1683. }
  1684. /// <summary>
  1685. /// Adds a hyperlink with an anchor to a document and creates a Paragraph which uses it.
  1686. /// </summary>
  1687. /// <param name="text">The text as displayed by the hyperlink.</param>
  1688. /// <param name="anchor">The anchor to a bookmark.</param>
  1689. /// <returns>Returns a hyperlink with an anchor that can be inserted into a Paragraph.</returns>
  1690. public Hyperlink AddHyperlink( string text, string anchor )
  1691. {
  1692. return this.AddHyperlink( text, null, anchor );
  1693. }
  1694. /// <summary>
  1695. /// Adds three new Headers to this document. One for the first page, one for odd pages and one for even pages.
  1696. /// </summary>
  1697. /// <example>
  1698. /// // Create a document.
  1699. /// using (DocX document = DocX.Create(@"Test.docx"))
  1700. /// {
  1701. /// // Add header support to this document.
  1702. /// document.AddHeaders();
  1703. ///
  1704. /// // Get a collection of all headers in this document.
  1705. /// Headers headers = document.Headers;
  1706. ///
  1707. /// // The header used for the first page of this document.
  1708. /// Header first = headers.first;
  1709. ///
  1710. /// // The header used for odd pages of this document.
  1711. /// Header odd = headers.odd;
  1712. ///
  1713. /// // The header used for even pages of this document.
  1714. /// Header even = headers.even;
  1715. ///
  1716. /// // Force the document to use a different header for first, odd and even pages.
  1717. /// document.DifferentFirstPage = true;
  1718. /// document.DifferentOddAndEvenPages = true;
  1719. ///
  1720. /// // Content can be added to the Headers in the same manor that it would be added to the main document.
  1721. /// Paragraph p = first.InsertParagraph();
  1722. /// p.Append("This is the first pages header.");
  1723. ///
  1724. /// // Save all changes to this document.
  1725. /// document.Save();
  1726. /// }// Release this document from memory.
  1727. /// </example>
  1728. public void AddHeaders()
  1729. {
  1730. this.AddHeadersOrFooters( true );
  1731. _headers.Odd = Document.GetHeaderByType( "default" );
  1732. _headers.Even = Document.GetHeaderByType( "even" );
  1733. _headers.First = Document.GetHeaderByType( "first" );
  1734. }
  1735. /// <summary>
  1736. /// Adds three new Footers to this document. One for the first page, one for odd pages and one for even pages.
  1737. /// </summary>
  1738. /// <example>
  1739. /// // Create a document.
  1740. /// using (DocX document = DocX.Create(@"Test.docx"))
  1741. /// {
  1742. /// // Add footer support to this document.
  1743. /// document.AddFooters();
  1744. ///
  1745. /// // Get a collection of all footers in this document.
  1746. /// Footers footers = document.Footers;
  1747. ///
  1748. /// // The footer used for the first page of this document.
  1749. /// Footer first = footers.first;
  1750. ///
  1751. /// // The footer used for odd pages of this document.
  1752. /// Footer odd = footers.odd;
  1753. ///
  1754. /// // The footer used for even pages of this document.
  1755. /// Footer even = footers.even;
  1756. ///
  1757. /// // Force the document to use a different footer for first, odd and even pages.
  1758. /// document.DifferentFirstPage = true;
  1759. /// document.DifferentOddAndEvenPages = true;
  1760. ///
  1761. /// // Content can be added to the Footers in the same manor that it would be added to the main document.
  1762. /// Paragraph p = first.InsertParagraph();
  1763. /// p.Append("This is the first pages footer.");
  1764. ///
  1765. /// // Save all changes to this document.
  1766. /// document.Save();
  1767. /// }// Release this document from memory.
  1768. /// </example>
  1769. public void AddFooters()
  1770. {
  1771. AddHeadersOrFooters( false );
  1772. _footers.Odd = Document.GetFooterByType( "default" );
  1773. _footers.Even = Document.GetFooterByType( "even" );
  1774. _footers.First = Document.GetFooterByType( "first" );
  1775. }
  1776. /// <summary>
  1777. /// Save this document back to the location it was loaded from.
  1778. /// </summary>
  1779. /// <example>
  1780. /// <code>
  1781. /// // Load a document.
  1782. /// using (DocX document = DocX.Load(@"C:\Example\Test.docx"))
  1783. /// {
  1784. /// // Add an Image from a file.
  1785. /// document.AddImage(@"C:\Example\Image.jpg");
  1786. ///
  1787. /// // Save all changes made to this document.
  1788. /// document.Save();
  1789. /// }// Release this document from memory.
  1790. /// </code>
  1791. /// </example>
  1792. /// <seealso cref="DocX.SaveAs(string)"/>
  1793. /// <seealso cref="DocX.Load(System.IO.Stream)"/>
  1794. /// <seealso cref="DocX.Load(string)"/>
  1795. /// <!--
  1796. /// Bug found and fixed by krugs525 on August 12 2009.
  1797. /// Use TFS compare to see exact code change.
  1798. /// -->
  1799. public void Save()
  1800. {
  1801. var headers = Headers;
  1802. // Save the main document
  1803. using( TextWriter tw = new StreamWriter( new PackagePartStream( this.PackagePart.GetStream( FileMode.Create, FileAccess.Write ) ) ) )
  1804. {
  1805. _mainDoc.Save( tw, SaveOptions.None );
  1806. }
  1807. if( (_settings == null) || !this.isProtected )
  1808. {
  1809. using( TextReader textReader = new StreamReader( _settingsPart.GetStream() ) )
  1810. {
  1811. _settings = XDocument.Load( textReader );
  1812. }
  1813. }
  1814. var body = _mainDoc.Root.Element( w + "body" );
  1815. var sectPr = body.Descendants( w + "sectPr" ).FirstOrDefault();
  1816. if( sectPr != null )
  1817. {
  1818. var evenHeaderRef =
  1819. (
  1820. from e in _mainDoc.Descendants( w + "headerReference" )
  1821. let type = e.Attribute( w + "type" )
  1822. where type != null && type.Value.Equals( "even", StringComparison.CurrentCultureIgnoreCase )
  1823. select e.Attribute( r + "id" ).Value
  1824. ).LastOrDefault();
  1825. if( evenHeaderRef != null )
  1826. {
  1827. var even = headers.Even.Xml;
  1828. var target = PackUriHelper.ResolvePartUri
  1829. (
  1830. this.PackagePart.Uri,
  1831. this.PackagePart.GetRelationship( evenHeaderRef ).TargetUri
  1832. );
  1833. using( TextWriter tw = new StreamWriter( new PackagePartStream( _package.GetPart( target ).GetStream( FileMode.Create, FileAccess.Write ) ) ) )
  1834. {
  1835. new XDocument
  1836. (
  1837. new XDeclaration( "1.0", "UTF-8", "yes" ),
  1838. even
  1839. ).Save( tw, SaveOptions.None );
  1840. }
  1841. }
  1842. var oddHeaderRef =
  1843. (
  1844. from e in _mainDoc.Descendants( w + "headerReference" )
  1845. let type = e.Attribute( w + "type" )
  1846. where type != null && type.Value.Equals( "default", StringComparison.CurrentCultureIgnoreCase )
  1847. select e.Attribute( r + "id" ).Value
  1848. ).LastOrDefault();
  1849. if( oddHeaderRef != null )
  1850. {
  1851. var odd = headers.Odd.Xml;
  1852. var target = PackUriHelper.ResolvePartUri
  1853. (
  1854. this.PackagePart.Uri,
  1855. this.PackagePart.GetRelationship( oddHeaderRef ).TargetUri
  1856. );
  1857. // Save header1
  1858. using( TextWriter tw = new StreamWriter( new PackagePartStream( _package.GetPart( target ).GetStream( FileMode.Create, FileAccess.Write ) ) ) )
  1859. {
  1860. new XDocument
  1861. (
  1862. new XDeclaration( "1.0", "UTF-8", "yes" ),
  1863. odd
  1864. ).Save( tw, SaveOptions.None );
  1865. }
  1866. }
  1867. var firstHeaderRef =
  1868. (
  1869. from e in _mainDoc.Descendants( w + "headerReference" )
  1870. let type = e.Attribute( w + "type" )
  1871. where type != null && type.Value.Equals( "first", StringComparison.CurrentCultureIgnoreCase )
  1872. select e.Attribute( r + "id" ).Value
  1873. ).LastOrDefault();
  1874. if( firstHeaderRef != null )
  1875. {
  1876. var first = headers.First.Xml;
  1877. var target = PackUriHelper.ResolvePartUri
  1878. (
  1879. this.PackagePart.Uri,
  1880. this.PackagePart.GetRelationship( firstHeaderRef ).TargetUri
  1881. );
  1882. // Save header3
  1883. using( TextWriter tw = new StreamWriter( new PackagePartStream( _package.GetPart( target ).GetStream( FileMode.Create, FileAccess.Write ) ) ) )
  1884. {
  1885. new XDocument
  1886. (
  1887. new XDeclaration( "1.0", "UTF-8", "yes" ),
  1888. first
  1889. ).Save( tw, SaveOptions.None );
  1890. }
  1891. }
  1892. var oddFooterRef =
  1893. (
  1894. from e in _mainDoc.Descendants( w + "footerReference" )
  1895. let type = e.Attribute( w + "type" )
  1896. where type != null && type.Value.Equals( "default", StringComparison.CurrentCultureIgnoreCase )
  1897. select e.Attribute( r + "id" ).Value
  1898. ).LastOrDefault();
  1899. if( oddFooterRef != null )
  1900. {
  1901. var odd = _footers.Odd.Xml;
  1902. var target = PackUriHelper.ResolvePartUri
  1903. (
  1904. this.PackagePart.Uri,
  1905. this.PackagePart.GetRelationship( oddFooterRef ).TargetUri
  1906. );
  1907. // Save header1
  1908. using( TextWriter tw = new StreamWriter( new PackagePartStream( _package.GetPart( target ).GetStream( FileMode.Create, FileAccess.Write ) ) ) )
  1909. {
  1910. new XDocument
  1911. (
  1912. new XDeclaration( "1.0", "UTF-8", "yes" ),
  1913. odd
  1914. ).Save( tw, SaveOptions.None );
  1915. }
  1916. }
  1917. var evenFooterRef =
  1918. (
  1919. from e in _mainDoc.Descendants( w + "footerReference" )
  1920. let type = e.Attribute( w + "type" )
  1921. where type != null && type.Value.Equals( "even", StringComparison.CurrentCultureIgnoreCase )
  1922. select e.Attribute( r + "id" ).Value
  1923. ).LastOrDefault();
  1924. if( evenFooterRef != null )
  1925. {
  1926. var even = _footers.Even.Xml;
  1927. var target = PackUriHelper.ResolvePartUri
  1928. (
  1929. this.PackagePart.Uri,
  1930. this.PackagePart.GetRelationship( evenFooterRef ).TargetUri
  1931. );
  1932. // Save header2
  1933. using( TextWriter tw = new StreamWriter( new PackagePartStream( _package.GetPart( target ).GetStream( FileMode.Create, FileAccess.Write ) ) ) )
  1934. {
  1935. new XDocument
  1936. (
  1937. new XDeclaration( "1.0", "UTF-8", "yes" ),
  1938. even
  1939. ).Save( tw, SaveOptions.None );
  1940. }
  1941. }
  1942. var firstFooterRef =
  1943. (
  1944. from e in _mainDoc.Descendants( w + "footerReference" )
  1945. let type = e.Attribute( w + "type" )
  1946. where type != null && type.Value.Equals( "first", StringComparison.CurrentCultureIgnoreCase )
  1947. select e.Attribute( r + "id" ).Value
  1948. ).LastOrDefault();
  1949. if( firstFooterRef != null )
  1950. {
  1951. var first = _footers.First.Xml;
  1952. var target = PackUriHelper.ResolvePartUri
  1953. (
  1954. this.PackagePart.Uri,
  1955. this.PackagePart.GetRelationship( firstFooterRef ).TargetUri
  1956. );
  1957. // Save header3
  1958. using( TextWriter tw = new StreamWriter( new PackagePartStream( _package.GetPart( target ).GetStream( FileMode.Create, FileAccess.Write ) ) ) )
  1959. {
  1960. new XDocument
  1961. (
  1962. new XDeclaration( "1.0", "UTF-8", "yes" ),
  1963. first
  1964. ).Save( tw, SaveOptions.None );
  1965. }
  1966. }
  1967. // Save the settings document.
  1968. using( TextWriter tw = new StreamWriter( new PackagePartStream( _settingsPart.GetStream( FileMode.Create, FileAccess.Write ) ) ) )
  1969. {
  1970. _settings.Save( tw, SaveOptions.None );
  1971. }
  1972. if( _endnotesPart != null )
  1973. {
  1974. using( TextWriter tw = new StreamWriter( new PackagePartStream( _endnotesPart.GetStream( FileMode.Create, FileAccess.Write ) ) ) )
  1975. {
  1976. _endnotes.Save( tw, SaveOptions.None );
  1977. }
  1978. }
  1979. if( _footnotesPart != null )
  1980. {
  1981. using( TextWriter tw = new StreamWriter( new PackagePartStream( _footnotesPart.GetStream( FileMode.Create, FileAccess.Write ) ) ) )
  1982. {
  1983. _footnotes.Save( tw, SaveOptions.None );
  1984. }
  1985. }
  1986. if( _stylesPart != null )
  1987. {
  1988. using( TextWriter tw = new StreamWriter( new PackagePartStream( _stylesPart.GetStream( FileMode.Create, FileAccess.Write ) ) ) )
  1989. {
  1990. _styles.Save( tw, SaveOptions.None );
  1991. }
  1992. }
  1993. if( _stylesWithEffectsPart != null )
  1994. {
  1995. using( TextWriter tw = new StreamWriter( new PackagePartStream( _stylesWithEffectsPart.GetStream( FileMode.Create, FileAccess.Write ) ) ) )
  1996. {
  1997. _stylesWithEffects.Save( tw, SaveOptions.None );
  1998. }
  1999. }
  2000. if( _numberingPart != null )
  2001. {
  2002. using( TextWriter tw = new StreamWriter( new PackagePartStream( _numberingPart.GetStream( FileMode.Create, FileAccess.Write ) ) ) )
  2003. {
  2004. _numbering.Save( tw, SaveOptions.None );
  2005. }
  2006. }
  2007. if( _fontTablePart != null )
  2008. {
  2009. using( TextWriter tw = new StreamWriter( new PackagePartStream( _fontTablePart.GetStream( FileMode.Create, FileAccess.Write ) ) ) )
  2010. {
  2011. _fontTable.Save( tw, SaveOptions.None );
  2012. }
  2013. }
  2014. }
  2015. // Close the document so that it can be saved.
  2016. _package.Flush();
  2017. #region Save this document back to a file or stream, that was specified by the user at save time.
  2018. if( _filename != null )
  2019. {
  2020. using( FileStream fs = new FileStream( _filename, FileMode.Create ) )
  2021. {
  2022. if( _memoryStream.CanSeek )
  2023. {
  2024. // Write to the beginning of the stream
  2025. _memoryStream.Position = 0;
  2026. CopyStream( _memoryStream, fs );
  2027. }
  2028. else
  2029. fs.Write( _memoryStream.ToArray(), 0, ( int )_memoryStream.Length );
  2030. }
  2031. }
  2032. else if( _stream.CanSeek ) //Check if stream can be seeked to support System.Web.HttpResponseStream.
  2033. {
  2034. // Set the length of this stream to 0
  2035. _stream.SetLength( 0 );
  2036. // Write to the beginning of the stream
  2037. _stream.Position = 0;
  2038. _memoryStream.WriteTo( _stream );
  2039. _memoryStream.Flush();
  2040. }
  2041. #endregion
  2042. }
  2043. /// <summary>
  2044. /// Save this document to a file.
  2045. /// </summary>
  2046. /// <param name="filename">The filename to save this document as.</param>
  2047. /// <example>
  2048. /// Load a document from one file and save it to another.
  2049. /// <code>
  2050. /// // Load a document using its fully qualified filename.
  2051. /// DocX document = DocX.Load(@"C:\Example\Test1.docx");
  2052. ///
  2053. /// // Insert a new Paragraph
  2054. /// document.InsertParagraph("Hello world!", false);
  2055. ///
  2056. /// // Save the document to a new location.
  2057. /// document.SaveAs(@"C:\Example\Test2.docx");
  2058. /// </code>
  2059. /// </example>
  2060. /// <example>
  2061. /// Load a document from a Stream and save it to a file.
  2062. /// <code>
  2063. /// DocX document;
  2064. /// using (FileStream fs1 = new FileStream(@"C:\Example\Test1.docx", FileMode.Open))
  2065. /// {
  2066. /// // Load a document using a stream.
  2067. /// document = DocX.Load(fs1);
  2068. ///
  2069. /// // Insert a new Paragraph
  2070. /// document.InsertParagraph("Hello world again!", false);
  2071. /// }
  2072. ///
  2073. /// // Save the document to a new location.
  2074. /// document.SaveAs(@"C:\Example\Test2.docx");
  2075. /// </code>
  2076. /// </example>
  2077. /// <seealso cref="DocX.Save()"/>
  2078. /// <seealso cref="DocX.Load(System.IO.Stream)"/>
  2079. /// <seealso cref="DocX.Load(string)"/>
  2080. public void SaveAs( string filename )
  2081. {
  2082. _filename = filename;
  2083. _stream = null;
  2084. Save();
  2085. }
  2086. /// <summary>
  2087. /// Save this document to a Stream.
  2088. /// </summary>
  2089. /// <param name="stream">The Stream to save this document to.</param>
  2090. /// <example>
  2091. /// Load a document from a file and save it to a Stream.
  2092. /// <code>
  2093. /// // Place holder for a document.
  2094. /// DocX document;
  2095. ///
  2096. /// using (FileStream fs1 = new FileStream(@"C:\Example\Test1.docx", FileMode.Open))
  2097. /// {
  2098. /// // Load a document using a stream.
  2099. /// document = DocX.Load(fs1);
  2100. ///
  2101. /// // Insert a new Paragraph
  2102. /// document.InsertParagraph("Hello world again!", false);
  2103. /// }
  2104. ///
  2105. /// using (FileStream fs2 = new FileStream(@"C:\Example\Test2.docx", FileMode.Create))
  2106. /// {
  2107. /// // Save the document to a different stream.
  2108. /// document.SaveAs(fs2);
  2109. /// }
  2110. ///
  2111. /// // Release this document from memory.
  2112. /// document.Dispose();
  2113. /// </code>
  2114. /// </example>
  2115. /// <example>
  2116. /// Load a document from one Stream and save it to another.
  2117. /// <code>
  2118. /// DocX document;
  2119. /// using (FileStream fs1 = new FileStream(@"C:\Example\Test1.docx", FileMode.Open))
  2120. /// {
  2121. /// // Load a document using a stream.
  2122. /// document = DocX.Load(fs1);
  2123. ///
  2124. /// // Insert a new Paragraph
  2125. /// document.InsertParagraph("Hello world again!", false);
  2126. /// }
  2127. ///
  2128. /// using (FileStream fs2 = new FileStream(@"C:\Example\Test2.docx", FileMode.Create))
  2129. /// {
  2130. /// // Save the document to a different stream.
  2131. /// document.SaveAs(fs2);
  2132. /// }
  2133. /// </code>
  2134. /// </example>
  2135. /// <seealso cref="DocX.Save()"/>
  2136. /// <seealso cref="DocX.Load(System.IO.Stream)"/>
  2137. /// <seealso cref="DocX.Load(string)"/>
  2138. public void SaveAs( Stream stream )
  2139. {
  2140. _filename = null;
  2141. _stream = stream;
  2142. Save();
  2143. }
  2144. /// <summary>
  2145. /// Add a core property to this document. If a core property already exists with the same name it will be replaced. Core property names are case insensitive.
  2146. /// </summary>
  2147. ///<param name="propertyName">The property name.</param>
  2148. ///<param name="propertyValue">The property value.</param>
  2149. ///<example>
  2150. /// Add a core properties of each type to a document.
  2151. /// <code>
  2152. /// // Load Example.docx
  2153. /// using (DocX document = DocX.Load(@"C:\Example\Test.docx"))
  2154. /// {
  2155. /// // If this document does not contain a core property called 'forename', create one.
  2156. /// if (!document.CoreProperties.ContainsKey("forename"))
  2157. /// {
  2158. /// // Create a new core property called 'forename' and set its value.
  2159. /// document.AddCoreProperty("forename", "Cathal");
  2160. /// }
  2161. ///
  2162. /// // Get this documents core property called 'forename'.
  2163. /// string forenameValue = document.CoreProperties["forename"];
  2164. ///
  2165. /// // Print all of the information about this core property to Console.
  2166. /// Console.WriteLine(string.Format("Name: '{0}', Value: '{1}'\nPress any key...", "forename", forenameValue));
  2167. ///
  2168. /// // Save all changes made to this document.
  2169. /// document.Save();
  2170. /// } // Release this document from memory.
  2171. ///
  2172. /// // Wait for the user to press a key before exiting.
  2173. /// Console.ReadKey();
  2174. /// </code>
  2175. /// </example>
  2176. /// <seealso cref="CoreProperties"/>
  2177. /// <seealso cref="CustomProperty"/>
  2178. /// <seealso cref="CustomProperties"/>
  2179. public void AddCoreProperty( string propertyName, string propertyValue )
  2180. {
  2181. var propertyNamespacePrefix = propertyName.Contains(":") ? propertyName.Split(':')[0] : "cp";
  2182. var propertyLocalName = propertyName.Contains(":") ? propertyName.Split(':')[1] : propertyName;
  2183. // If this document does not contain a coreFilePropertyPart create one.)
  2184. if( !_package.PartExists( new Uri( "/docProps/core.xml", UriKind.Relative ) ) )
  2185. throw new Exception( "Core properties part doesn't exist." );
  2186. XDocument corePropDoc;
  2187. var corePropPart = _package.GetPart( new Uri( "/docProps/core.xml", UriKind.Relative ) );
  2188. using( TextReader tr = new StreamReader( corePropPart.GetStream( FileMode.Open, FileAccess.Read ) ) )
  2189. {
  2190. corePropDoc = XDocument.Load( tr );
  2191. }
  2192. var corePropElement =
  2193. ( from propElement in corePropDoc.Root.Elements()
  2194. where ( propElement.Name.LocalName.Equals( propertyLocalName ) )
  2195. select propElement ).SingleOrDefault();
  2196. if( corePropElement != null )
  2197. {
  2198. corePropElement.SetValue( propertyValue );
  2199. }
  2200. else
  2201. {
  2202. var propertyNamespace = corePropDoc.Root.GetNamespaceOfPrefix( propertyNamespacePrefix );
  2203. corePropDoc.Root.Add( new XElement( XName.Get( propertyLocalName, propertyNamespace.NamespaceName ), propertyValue ) );
  2204. }
  2205. using( TextWriter tw = new StreamWriter( new PackagePartStream( corePropPart.GetStream( FileMode.Create, FileAccess.Write ) ) ) )
  2206. {
  2207. corePropDoc.Save( tw );
  2208. }
  2209. DocX.UpdateCorePropertyValue( this, propertyLocalName, propertyValue );
  2210. }
  2211. /// <summary>
  2212. /// Add a custom property to this document. If a custom property already exists with the same name it will be replace. CustomProperty names are case insensitive.
  2213. /// </summary>
  2214. /// <param name="cp">The CustomProperty to add to this document.</param>
  2215. /// <example>
  2216. /// Add a custom properties of each type to a document.
  2217. /// <code>
  2218. /// // Load Example.docx
  2219. /// using (DocX document = DocX.Load(@"C:\Example\Test.docx"))
  2220. /// {
  2221. /// // A CustomProperty called forename which stores a string.
  2222. /// CustomProperty forename;
  2223. ///
  2224. /// // If this document does not contain a custom property called 'forename', create one.
  2225. /// if (!document.CustomProperties.ContainsKey("forename"))
  2226. /// {
  2227. /// // Create a new custom property called 'forename' and set its value.
  2228. /// document.AddCustomProperty(new CustomProperty("forename", "Cathal"));
  2229. /// }
  2230. ///
  2231. /// // Get this documents custom property called 'forename'.
  2232. /// forename = document.CustomProperties["forename"];
  2233. ///
  2234. /// // Print all of the information about this CustomProperty to Console.
  2235. /// Console.WriteLine(string.Format("Name: '{0}', Value: '{1}'\nPress any key...", forename.Name, forename.Value));
  2236. ///
  2237. /// // Save all changes made to this document.
  2238. /// document.Save();
  2239. /// } // Release this document from memory.
  2240. ///
  2241. /// // Wait for the user to press a key before exiting.
  2242. /// Console.ReadKey();
  2243. /// </code>
  2244. /// </example>
  2245. /// <seealso cref="CustomProperty"/>
  2246. /// <seealso cref="CustomProperties"/>
  2247. public void AddCustomProperty( CustomProperty cp )
  2248. {
  2249. // If this document does not contain a customFilePropertyPart create one.
  2250. if( !_package.PartExists( new Uri( "/docProps/custom.xml", UriKind.Relative ) ) )
  2251. {
  2252. HelperFunctions.CreateCustomPropertiesPart( this );
  2253. }
  2254. XDocument customPropDoc;
  2255. var customPropPart = _package.GetPart( new Uri( "/docProps/custom.xml", UriKind.Relative ) );
  2256. using( TextReader tr = new StreamReader( customPropPart.GetStream( FileMode.Open, FileAccess.Read ) ) )
  2257. {
  2258. customPropDoc = XDocument.Load( tr, LoadOptions.PreserveWhitespace );
  2259. }
  2260. // Each custom property has a PID, get the highest PID in this document.
  2261. IEnumerable<int> pids =
  2262. (
  2263. from d in customPropDoc.Descendants()
  2264. where d.Name.LocalName == "property"
  2265. select int.Parse( d.Attribute( XName.Get( "pid" ) ).Value )
  2266. );
  2267. int pid = 1;
  2268. if( pids.Count() > 0 )
  2269. {
  2270. pid = pids.Max();
  2271. }
  2272. // Check if a custom property already exists with this name
  2273. var customProperty =
  2274. (
  2275. from d in customPropDoc.Descendants()
  2276. where ( d.Name.LocalName == "property" ) && ( d.Attribute( XName.Get( "name" ) ).Value.Equals( cp.Name, StringComparison.InvariantCultureIgnoreCase ) )
  2277. select d
  2278. ).SingleOrDefault();
  2279. // If a custom property with this name already exists remove it.
  2280. if( customProperty != null )
  2281. {
  2282. customProperty.Remove();
  2283. }
  2284. var propertiesElement = customPropDoc.Element( XName.Get( "Properties", customPropertiesSchema.NamespaceName ) );
  2285. propertiesElement.Add
  2286. (
  2287. new XElement
  2288. (
  2289. XName.Get( "property", customPropertiesSchema.NamespaceName ),
  2290. new XAttribute( "fmtid", "{D5CDD505-2E9C-101B-9397-08002B2CF9AE}" ),
  2291. new XAttribute( "pid", pid + 1 ),
  2292. new XAttribute( "name", cp.Name ),
  2293. new XElement( customVTypesSchema + cp.Type, cp.Value ?? "" )
  2294. )
  2295. );
  2296. // Save the custom properties
  2297. using( TextWriter tw = new StreamWriter( new PackagePartStream( customPropPart.GetStream( FileMode.Create, FileAccess.Write ) ) ) )
  2298. {
  2299. customPropDoc.Save( tw, SaveOptions.None );
  2300. }
  2301. // Refresh all fields in this document which display this custom property.
  2302. DocX.UpdateCustomPropertyValue( this, cp.Name, ( cp.Value ?? "" ).ToString() );
  2303. }
  2304. public override Paragraph InsertParagraph()
  2305. {
  2306. var p = base.InsertParagraph();
  2307. p.PackagePart = this.PackagePart;
  2308. return p;
  2309. }
  2310. public override Paragraph InsertParagraph( int index, string text, bool trackChanges )
  2311. {
  2312. var p = base.InsertParagraph( index, text, trackChanges );
  2313. p.PackagePart = this.PackagePart;
  2314. return p;
  2315. }
  2316. public override Paragraph InsertParagraph( Paragraph p )
  2317. {
  2318. p.PackagePart = this.PackagePart;
  2319. return base.InsertParagraph( p );
  2320. }
  2321. public override Paragraph InsertParagraph( int index, Paragraph p )
  2322. {
  2323. p.PackagePart = this.PackagePart;
  2324. return base.InsertParagraph( index, p );
  2325. }
  2326. public override Paragraph InsertParagraph( int index, string text, bool trackChanges, Formatting formatting )
  2327. {
  2328. var p = base.InsertParagraph( index, text, trackChanges, formatting );
  2329. p.PackagePart = this.PackagePart;
  2330. return p;
  2331. }
  2332. public override Paragraph InsertParagraph( string text )
  2333. {
  2334. var p = base.InsertParagraph( text );
  2335. p.PackagePart = this.PackagePart;
  2336. return p;
  2337. }
  2338. public override Paragraph InsertParagraph( string text, bool trackChanges )
  2339. {
  2340. var p = base.InsertParagraph( text, trackChanges );
  2341. p.PackagePart = this.PackagePart;
  2342. return p;
  2343. }
  2344. public override Paragraph InsertParagraph( string text, bool trackChanges, Formatting formatting )
  2345. {
  2346. var p = base.InsertParagraph( text, trackChanges, formatting );
  2347. p.PackagePart = this.PackagePart;
  2348. return p;
  2349. }
  2350. public Paragraph[] InsertParagraphs( string text )
  2351. {
  2352. var textArray = text.Split( '\n' );
  2353. var paragraphs = new List<Paragraph>();
  2354. foreach( var textForParagraph in textArray )
  2355. {
  2356. var p = base.InsertParagraph( text );
  2357. p.PackagePart = this.PackagePart;
  2358. paragraphs.Add( p );
  2359. }
  2360. return paragraphs.ToArray();
  2361. }
  2362. /// <summary>
  2363. /// Create an equation and insert it in the new paragraph
  2364. /// </summary>
  2365. public override Paragraph InsertEquation( String equation )
  2366. {
  2367. var p = base.InsertEquation( equation );
  2368. p.PackagePart = this.PackagePart;
  2369. return p;
  2370. }
  2371. /// <summary>
  2372. /// Insert a chart in document
  2373. /// </summary>
  2374. public void InsertChart( Chart chart )
  2375. {
  2376. this.InsertChart( chart, null );
  2377. }
  2378. /// <summary>
  2379. /// Insert a chart in document after the specified paragraph
  2380. /// </summary>
  2381. public void InsertChartAfterParagraph( Chart chart, Paragraph paragraph )
  2382. {
  2383. this.InsertChart( chart, paragraph );
  2384. }
  2385. private void InsertChart( Chart chart, Paragraph paragraph )
  2386. {
  2387. Paragraph p;
  2388. // Create a new chart part uri.
  2389. var chartPartUriPath = String.Empty;
  2390. var chartIndex = 1;
  2391. do
  2392. {
  2393. chartPartUriPath = String.Format( "/word/charts/chart{0}.xml", chartIndex );
  2394. chartIndex++;
  2395. } while( _package.PartExists( new Uri( chartPartUriPath, UriKind.Relative ) ) );
  2396. // Create chart part.
  2397. var chartPackagePart = _package.CreatePart( new Uri( chartPartUriPath, UriKind.Relative ), "application/vnd.openxmlformats-officedocument.drawingml.chart+xml", CompressionOption.Normal );
  2398. // Create a new chart relationship
  2399. var relID = this.GetNextFreeRelationshipID();
  2400. var rel = this.PackagePart.CreateRelationship( chartPackagePart.Uri, TargetMode.Internal, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart", relID );
  2401. // Save a chart info the chartPackagePart
  2402. if( paragraph == null )
  2403. {
  2404. using( TextWriter tw = new StreamWriter( new PackagePartStream( chartPackagePart.GetStream( FileMode.Create, FileAccess.Write ) ) ) )
  2405. {
  2406. chart.Xml.Save( tw );
  2407. }
  2408. p = InsertParagraph();
  2409. }
  2410. else
  2411. {
  2412. using( TextWriter tw = new StreamWriter( chartPackagePart.GetStream( FileMode.Create, FileAccess.Write ) ) )
  2413. {
  2414. chart.Xml.Save( tw );
  2415. }
  2416. p = paragraph;
  2417. }
  2418. // Insert a new chart into a paragraph.
  2419. var chartElement = new XElement( XName.Get( "r", w.NamespaceName ),
  2420. new XElement( XName.Get( "drawing", w.NamespaceName ),
  2421. new XElement( XName.Get( "inline", wp.NamespaceName ),
  2422. new XElement( XName.Get( "extent", wp.NamespaceName ), new XAttribute( "cx", "5486400" ), new XAttribute( "cy", "3200400" ) ),
  2423. new XElement( XName.Get( "effectExtent", wp.NamespaceName ), new XAttribute( "l", "0" ), new XAttribute( "t", "0" ), new XAttribute( "r", "19050" ), new XAttribute( "b", "19050" ) ),
  2424. new XElement( XName.Get( "docPr", wp.NamespaceName ), new XAttribute( "id", "1" ), new XAttribute( "name", "chart" ) ),
  2425. new XElement( XName.Get( "graphic", a.NamespaceName ),
  2426. new XElement( XName.Get( "graphicData", a.NamespaceName ),
  2427. new XAttribute( "uri", c.NamespaceName ),
  2428. new XElement( XName.Get( "chart", c.NamespaceName ),
  2429. new XAttribute( XName.Get( "id", r.NamespaceName ), relID ) ) ) ) ) ) );
  2430. p.Xml.Add( chartElement );
  2431. }
  2432. public List<Section> GetSections()
  2433. {
  2434. var paragraphs = Paragraphs;
  2435. var sections = new List<Section>();
  2436. var sectionParagraphs = new List<Paragraph>();
  2437. foreach( Paragraph paragraph in paragraphs )
  2438. {
  2439. var sectionInPara = paragraph.Xml.Descendants().FirstOrDefault( s => s.Name.LocalName == "sectPr" );
  2440. if( sectionInPara != null )
  2441. {
  2442. sectionParagraphs.Add( paragraph );
  2443. var section = new Section( Document, sectionInPara );
  2444. section.SectionParagraphs = sectionParagraphs;
  2445. sections.Add( section );
  2446. sectionParagraphs = new List<Paragraph>();
  2447. }
  2448. else
  2449. {
  2450. sectionParagraphs.Add( paragraph );
  2451. }
  2452. }
  2453. XElement body = _mainDoc.Root.Element( XName.Get( "body", w.NamespaceName ) );
  2454. XElement baseSectionXml = body.Element( XName.Get( "sectPr", w.NamespaceName ) );
  2455. var baseSection = new Section( Document, baseSectionXml );
  2456. baseSection.SectionParagraphs = sectionParagraphs;
  2457. sections.Add( baseSection );
  2458. return sections;
  2459. }
  2460. /// <summary>
  2461. /// Create a new List
  2462. /// </summary>
  2463. public List AddList( string listText = null, int level = 0, ListItemType listType = ListItemType.Numbered, int? startNumber = null, bool trackChanges = false, bool continueNumbering = false )
  2464. {
  2465. return AddListItem( new List( this, null ), listText, level, listType, startNumber, trackChanges, continueNumbering );
  2466. }
  2467. /// <summary>
  2468. /// Add a list item to an existing list
  2469. /// </summary>
  2470. public List AddListItem( List list, string listText, int level = 0, ListItemType listType = ListItemType.Numbered, int? startNumber = null, bool trackChanges = false, bool continueNumbering = false )
  2471. {
  2472. if( startNumber.HasValue && continueNumbering )
  2473. throw new InvalidOperationException( "Cannot specify a start number and at the same time continue numbering from another list" );
  2474. var result = HelperFunctions.CreateItemInList( list, listText, level, listType, startNumber, trackChanges, continueNumbering );
  2475. var lastItem = result.Items.LastOrDefault();
  2476. if( lastItem != null )
  2477. {
  2478. lastItem.PackagePart = this.PackagePart;
  2479. }
  2480. return result;
  2481. }
  2482. /// <summary>
  2483. /// Insert a list in the document
  2484. /// </summary>
  2485. /// <param name="list">The list to insert into the document.</param>
  2486. /// <returns>The list that was inserted into the document.</returns>
  2487. public override List InsertList( List list )
  2488. {
  2489. base.InsertList( list );
  2490. return list;
  2491. }
  2492. public override List InsertList( List list, Font fontFamily, double fontSize )
  2493. {
  2494. base.InsertList( list, fontFamily, fontSize );
  2495. return list;
  2496. }
  2497. public override List InsertList( List list, double fontSize )
  2498. {
  2499. base.InsertList( list, fontSize );
  2500. return list;
  2501. }
  2502. /// <summary>
  2503. /// Insert a list at an index location in the document
  2504. /// </summary>
  2505. /// <param name="index">Index in document to insert the list.</param>
  2506. /// <param name="list">The list that was inserted into the document.</param>
  2507. /// <returns></returns>
  2508. public new List InsertList( int index, List list )
  2509. {
  2510. base.InsertList( index, list );
  2511. return list;
  2512. }
  2513. /// <summary>
  2514. /// Insert a default Table of Contents in the current document
  2515. /// </summary>
  2516. public TableOfContents InsertDefaultTableOfContents()
  2517. {
  2518. return InsertTableOfContents( "Table of contents", TableOfContentsSwitches.O | TableOfContentsSwitches.H | TableOfContentsSwitches.Z | TableOfContentsSwitches.U );
  2519. }
  2520. /// <summary>
  2521. /// Insert a Table of Contents in the current document
  2522. /// </summary>
  2523. public TableOfContents InsertTableOfContents( string title, TableOfContentsSwitches switches, string headerStyle = null, int maxIncludeLevel = 3, int? rightTabPos = null )
  2524. {
  2525. var toc = TableOfContents.CreateTableOfContents( this, title, switches, headerStyle, maxIncludeLevel, rightTabPos );
  2526. Xml.Add( toc.Xml );
  2527. return toc;
  2528. }
  2529. /// <summary>
  2530. /// Insert a Table of Contents in the current document at a specific location (prior to the referenced paragraph)
  2531. /// </summary>
  2532. public TableOfContents InsertTableOfContents( Paragraph reference, string title, TableOfContentsSwitches switches, string headerStyle = null, int maxIncludeLevel = 3, int? rightTabPos = null )
  2533. {
  2534. var toc = TableOfContents.CreateTableOfContents( this, title, switches, headerStyle, maxIncludeLevel, rightTabPos );
  2535. reference.Xml.AddBeforeSelf( toc.Xml );
  2536. return toc;
  2537. }
  2538. /// <summary>
  2539. /// Copy the Document into a new Document
  2540. /// </summary>
  2541. /// <returns>Returns a copy of a the Document</returns>
  2542. public DocX Copy()
  2543. {
  2544. var memorystream = new MemoryStream();
  2545. this.SaveAs( memorystream );
  2546. memorystream.Seek( 0, SeekOrigin.Begin );
  2547. return Load( memorystream );
  2548. }
  2549. public void AddPasswordProtection( EditRestrictions editRestrictions, string password )
  2550. {
  2551. // Intellectual Property information :
  2552. //
  2553. // The following code handles password protection of Word documents (Open Specifications)
  2554. // and is an implementation of algorithm(s) described in Office Document Cryptography Structure
  2555. // here: https://msdn.microsoft.com/en-us/library/cc313071.aspx.
  2556. //
  2557. // The code’s use is covered under Microsoft’s Open Specification Promise
  2558. // described here: https://msdn.microsoft.com/en-US/openspecifications/dn646765
  2559. // Remove existing password protection
  2560. this.RemoveProtection();
  2561. // If no EditRestrictions, nothing to do
  2562. if( editRestrictions == EditRestrictions.none )
  2563. return;
  2564. // Variables
  2565. int maxPasswordLength = 15;
  2566. var saltArray = new byte[ 16 ];
  2567. var keyValues = new byte[ 14 ];
  2568. // Init DocumentProtection element
  2569. var documentProtection = new XElement( XName.Get( "documentProtection", w.NamespaceName ) );
  2570. documentProtection.Add( new XAttribute( XName.Get( "edit", w.NamespaceName ), editRestrictions.ToString() ) );
  2571. documentProtection.Add( new XAttribute( XName.Get( "enforcement", w.NamespaceName ), "1" ) );
  2572. int[] InitialCodeArray = { 0xE1F0, 0x1D0F, 0xCC9C, 0x84C0, 0x110C, 0x0E10, 0xF1CE, 0x313E, 0x1872, 0xE139, 0xD40F, 0x84F9, 0x280C, 0xA96A, 0x4EC3 };
  2573. int[,] EncryptionMatrix = new int[ 15, 7 ]
  2574. {
  2575. /* char 1 */ { 0xAEFC, 0x4DD9, 0x9BB2, 0x2745, 0x4E8A, 0x9D14, 0x2A09},
  2576. /* char 2 */ { 0x7B61, 0xF6C2, 0xFDA5, 0xEB6B, 0xC6F7, 0x9DCF, 0x2BBF},
  2577. /* char 3 */ { 0x4563, 0x8AC6, 0x05AD, 0x0B5A, 0x16B4, 0x2D68, 0x5AD0},
  2578. /* char 4 */ { 0x0375, 0x06EA, 0x0DD4, 0x1BA8, 0x3750, 0x6EA0, 0xDD40},
  2579. /* char 5 */ { 0xD849, 0xA0B3, 0x5147, 0xA28E, 0x553D, 0xAA7A, 0x44D5},
  2580. /* char 6 */ { 0x6F45, 0xDE8A, 0xAD35, 0x4A4B, 0x9496, 0x390D, 0x721A},
  2581. /* char 7 */ { 0xEB23, 0xC667, 0x9CEF, 0x29FF, 0x53FE, 0xA7FC, 0x5FD9},
  2582. /* char 8 */ { 0x47D3, 0x8FA6, 0x0F6D, 0x1EDA, 0x3DB4, 0x7B68, 0xF6D0},
  2583. /* char 9 */ { 0xB861, 0x60E3, 0xC1C6, 0x93AD, 0x377B, 0x6EF6, 0xDDEC},
  2584. /* char 10 */ { 0x45A0, 0x8B40, 0x06A1, 0x0D42, 0x1A84, 0x3508, 0x6A10},
  2585. /* char 11 */ { 0xAA51, 0x4483, 0x8906, 0x022D, 0x045A, 0x08B4, 0x1168},
  2586. /* char 12 */ { 0x76B4, 0xED68, 0xCAF1, 0x85C3, 0x1BA7, 0x374E, 0x6E9C},
  2587. /* char 13 */ { 0x3730, 0x6E60, 0xDCC0, 0xA9A1, 0x4363, 0x86C6, 0x1DAD},
  2588. /* char 14 */ { 0x3331, 0x6662, 0xCCC4, 0x89A9, 0x0373, 0x06E6, 0x0DCC},
  2589. /* char 15 */ { 0x1021, 0x2042, 0x4084, 0x8108, 0x1231, 0x2462, 0x48C4}
  2590. };
  2591. // Generate the salt
  2592. var random = new RNGCryptoServiceProvider();
  2593. random.GetNonZeroBytes( saltArray );
  2594. // Validate the provided password
  2595. if( !String.IsNullOrEmpty( password ) )
  2596. {
  2597. password = password.Substring( 0, Math.Min( password.Length, maxPasswordLength ) );
  2598. var byteChars = new byte[ password.Length ];
  2599. for( int i = 0; i < password.Length; i++ )
  2600. {
  2601. var temp = Convert.ToInt32( password[ i ] );
  2602. byteChars[ i ] = Convert.ToByte( temp & 0x00FF );
  2603. if( byteChars[ i ] == 0 )
  2604. {
  2605. byteChars[ i ] = Convert.ToByte( ( temp & 0x00FF ) >> 8 );
  2606. }
  2607. }
  2608. var intHighOrderWord = InitialCodeArray[ byteChars.Length - 1 ];
  2609. for( int i = 0; i < byteChars.Length; i++ )
  2610. {
  2611. int tmp = maxPasswordLength - byteChars.Length + i;
  2612. for( int intBit = 0; intBit < 7; intBit++ )
  2613. {
  2614. if( ( byteChars[ i ] & ( 0x0001 << intBit ) ) != 0 )
  2615. {
  2616. intHighOrderWord ^= EncryptionMatrix[ tmp, intBit ];
  2617. }
  2618. }
  2619. }
  2620. int intLowOrderWord = 0;
  2621. // For each character in the strPassword, going backwards
  2622. for( int i = byteChars.Length - 1; i >= 0; i-- )
  2623. {
  2624. intLowOrderWord = ( ( ( intLowOrderWord >> 14 ) & 0x0001 ) | ( ( intLowOrderWord << 1 ) & 0x7FFF ) ) ^ byteChars[ i ];
  2625. }
  2626. intLowOrderWord = ( ( ( intLowOrderWord >> 14 ) & 0x0001 ) | ( ( intLowOrderWord << 1 ) & 0x7FFF ) ) ^ byteChars.Length ^ 0xCE4B;
  2627. // Combine the Low and High Order Word
  2628. var intCombinedkey = ( intHighOrderWord << 16 ) + intLowOrderWord;
  2629. // The byte order of the result shall be reversed [Example: 0x64CEED7E becomes 7EEDCE64. end example],
  2630. // and that value shall be hashed as defined by the attribute values.
  2631. for( int i = 0; i < 4; i++ )
  2632. {
  2633. keyValues[ i ] = Convert.ToByte( ( ( uint )( intCombinedkey & ( 0x000000FF << ( i * 8 ) ) ) ) >> ( i * 8 ) );
  2634. }
  2635. }
  2636. var sb = new StringBuilder();
  2637. for( int intTemp = 0; intTemp < 4; intTemp++ )
  2638. {
  2639. sb.Append( Convert.ToString( keyValues[ intTemp ], 16 ) );
  2640. }
  2641. keyValues = Encoding.Unicode.GetBytes( sb.ToString().ToUpper() );
  2642. keyValues = MergeArrays( keyValues, saltArray );
  2643. int iterations = 100000;
  2644. var sha1 = new SHA1Managed();
  2645. keyValues = sha1.ComputeHash( keyValues );
  2646. var iterator = new byte[ 4 ];
  2647. for( int i = 0; i < iterations; i++ )
  2648. {
  2649. iterator[ 0 ] = Convert.ToByte( ( i & 0x000000FF ) >> 0 );
  2650. iterator[ 1 ] = Convert.ToByte( ( i & 0x0000FF00 ) >> 8 );
  2651. iterator[ 2 ] = Convert.ToByte( ( i & 0x00FF0000 ) >> 16 );
  2652. iterator[ 3 ] = Convert.ToByte( ( i & 0xFF000000 ) >> 24 );
  2653. keyValues = MergeArrays( iterator, keyValues );
  2654. keyValues = sha1.ComputeHash( keyValues );
  2655. }
  2656. documentProtection.Add( new XAttribute( XName.Get( "cryptProviderType", w.NamespaceName ), "rsaFull" ) );
  2657. documentProtection.Add( new XAttribute( XName.Get( "cryptAlgorithmClass", w.NamespaceName ), "hash" ) );
  2658. documentProtection.Add( new XAttribute( XName.Get( "cryptAlgorithmType", w.NamespaceName ), "typeAny" ) );
  2659. documentProtection.Add( new XAttribute( XName.Get( "cryptAlgorithmSid", w.NamespaceName ), "4" ) );
  2660. documentProtection.Add( new XAttribute( XName.Get( "cryptSpinCount", w.NamespaceName ), iterations.ToString() ) );
  2661. documentProtection.Add( new XAttribute( XName.Get( "hash", w.NamespaceName ), Convert.ToBase64String( keyValues ) ) );
  2662. documentProtection.Add( new XAttribute( XName.Get( "salt", w.NamespaceName ), Convert.ToBase64String( saltArray ) ) );
  2663. _settings.Root.AddFirst( documentProtection );
  2664. }
  2665. #endregion
  2666. #region Internal Methods
  2667. internal float getMarginAttribute( XName name )
  2668. {
  2669. var body = _mainDoc.Root.Element( XName.Get( "body", w.NamespaceName ) );
  2670. var sectPr = body.Element( XName.Get( "sectPr", w.NamespaceName ) );
  2671. var pgMar = sectPr?.Element( XName.Get( "pgMar", w.NamespaceName ) );
  2672. var top = pgMar?.Attribute( name );
  2673. if( top != null )
  2674. {
  2675. float f;
  2676. if( float.TryParse( top.Value, out f ) )
  2677. return ( int )( f / _pageSizeMultiplier );
  2678. }
  2679. return 0;
  2680. }
  2681. internal void setMarginAttribute( XName xName, float value )
  2682. {
  2683. var body = _mainDoc.Root.Element( XName.Get( "body", w.NamespaceName ) );
  2684. var sectPr = body.Element( XName.Get( "sectPr", w.NamespaceName ) );
  2685. var pgMar = sectPr?.Element( XName.Get( "pgMar", w.NamespaceName ) );
  2686. var top = pgMar?.Attribute( xName );
  2687. top?.SetValue( value * Convert.ToInt32( _pageSizeMultiplier ) );
  2688. }
  2689. internal string GetCollectiveText( List<PackagePart> list )
  2690. {
  2691. var text = string.Empty;
  2692. foreach( var hp in list )
  2693. {
  2694. using( TextReader tr = new StreamReader( hp.GetStream() ) )
  2695. {
  2696. var d = XDocument.Load( tr );
  2697. var sb = new StringBuilder();
  2698. // Loop through each text item in this run
  2699. foreach( XElement descendant in d.Descendants() )
  2700. {
  2701. switch( descendant.Name.LocalName )
  2702. {
  2703. case "tab":
  2704. sb.Append( "\t" );
  2705. break;
  2706. case "br":
  2707. sb.Append( "\n" );
  2708. break;
  2709. case "t":
  2710. goto case "delText";
  2711. case "delText":
  2712. sb.Append( descendant.Value );
  2713. break;
  2714. default:
  2715. break;
  2716. }
  2717. }
  2718. text += "\n" + sb;
  2719. }
  2720. }
  2721. return text;
  2722. }
  2723. internal static void PostCreation( Package package, DocumentTypes documentType = DocumentTypes.Document )
  2724. {
  2725. XDocument mainDoc, stylesDoc, numberingDoc;
  2726. #region MainDocumentPart
  2727. // Create the main document part for this package
  2728. var mainDocPart = ( documentType == DocumentTypes.Document )
  2729. ? package.CreatePart( new Uri( "/word/document.xml", UriKind.Relative ), HelperFunctions.DOCUMENT_DOCUMENTTYPE, CompressionOption.Normal )
  2730. : package.CreatePart( new Uri( "/word/document.xml", UriKind.Relative ), HelperFunctions.TEMPLATE_DOCUMENTTYPE, CompressionOption.Normal );
  2731. package.CreateRelationship( mainDocPart.Uri, TargetMode.Internal, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" );
  2732. // Load the document part into a XDocument object
  2733. using( TextReader tr = new StreamReader( mainDocPart.GetStream( FileMode.Create, FileAccess.ReadWrite ) ) )
  2734. {
  2735. mainDoc = XDocument.Parse
  2736. ( @"<?xml version=""1.0"" encoding=""UTF-8"" standalone=""yes""?>
  2737. <w:document xmlns:ve=""http://schemas.openxmlformats.org/markup-compatibility/2006"" 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:wp=""http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing"" xmlns:w10=""urn:schemas-microsoft-com:office:word"" xmlns:w=""http://schemas.openxmlformats.org/wordprocessingml/2006/main"" xmlns:wne=""http://schemas.microsoft.com/office/word/2006/wordml"" xmlns:a=""http://schemas.openxmlformats.org/drawingml/2006/main"" xmlns:c=""http://schemas.openxmlformats.org/drawingml/2006/chart"">
  2738. <w:body>
  2739. <w:sectPr w:rsidR=""003E25F4"" w:rsidSect=""00FC3028"">
  2740. <w:pgSz w:w=""11906"" w:h=""16838""/>
  2741. <w:pgMar w:top=""1440"" w:right=""1440"" w:bottom=""1440"" w:left=""1440"" w:header=""708"" w:footer=""708"" w:gutter=""0""/>
  2742. <w:cols w:space=""708""/>
  2743. <w:docGrid w:linePitch=""360""/>
  2744. </w:sectPr>
  2745. </w:body>
  2746. </w:document>"
  2747. );
  2748. }
  2749. // Save the main document
  2750. using( TextWriter tw = new StreamWriter( new PackagePartStream( mainDocPart.GetStream( FileMode.Create, FileAccess.Write ) ) ) )
  2751. {
  2752. mainDoc.Save( tw, SaveOptions.None );
  2753. }
  2754. #endregion
  2755. #region StylePart
  2756. stylesDoc = HelperFunctions.AddDefaultStylesXml( package );
  2757. #endregion
  2758. #region NumberingPart
  2759. numberingDoc = HelperFunctions.AddDefaultNumberingXml( package );
  2760. #endregion
  2761. package.Close();
  2762. }
  2763. internal static DocX PostLoad( ref Package package )
  2764. {
  2765. var document = new DocX( null, null );
  2766. document._package = package;
  2767. document.Document = document;
  2768. #region MainDocumentPart
  2769. document.PackagePart = HelperFunctions.GetMainDocumentPart( package );
  2770. using( TextReader tr = new StreamReader( document.PackagePart.GetStream( FileMode.Open, FileAccess.Read ) ) )
  2771. {
  2772. document._mainDoc = XDocument.Load( tr, LoadOptions.PreserveWhitespace );
  2773. }
  2774. #endregion
  2775. DocX.PopulateDocument( document, package );
  2776. using( TextReader tr = new StreamReader( document._settingsPart.GetStream() ) )
  2777. {
  2778. document._settings = XDocument.Load( tr );
  2779. }
  2780. document._paragraphLookup.Clear();
  2781. var paragraphs = document.Paragraphs;
  2782. foreach( var p in paragraphs )
  2783. {
  2784. if( !document._paragraphLookup.ContainsKey( p._endIndex ) )
  2785. {
  2786. document._paragraphLookup.Add( p._endIndex, p );
  2787. }
  2788. }
  2789. return document;
  2790. }
  2791. internal void AddHyperlinkStyleIfNotPresent()
  2792. {
  2793. var word_styles_Uri = new Uri( "/word/styles.xml", UriKind.Relative );
  2794. // If the internal document contains no /word/styles.xml create one.
  2795. if( !_package.PartExists( word_styles_Uri ) )
  2796. {
  2797. HelperFunctions.AddDefaultStylesXml( _package );
  2798. }
  2799. // Load the styles.xml into memory.
  2800. XDocument word_styles;
  2801. using( TextReader tr = new StreamReader( _package.GetPart( word_styles_Uri ).GetStream() ) )
  2802. {
  2803. word_styles = XDocument.Load( tr );
  2804. }
  2805. bool hyperlinkStyleExists =
  2806. (
  2807. from s in word_styles.Element( w + "styles" ).Elements()
  2808. let styleId = s.Attribute( XName.Get( "styleId", w.NamespaceName ) )
  2809. where ( styleId != null && styleId.Value == "Hyperlink" )
  2810. select s
  2811. ).Count() > 0;
  2812. if( !hyperlinkStyleExists )
  2813. {
  2814. var style = new XElement
  2815. (
  2816. w + "style",
  2817. new XAttribute( w + "type", "character" ),
  2818. new XAttribute( w + "styleId", "Hyperlink" ),
  2819. new XElement( w + "name", new XAttribute( w + "val", "Hyperlink" ) ),
  2820. new XElement( w + "basedOn", new XAttribute( w + "val", "DefaultParagraphFont" ) ),
  2821. new XElement( w + "uiPriority", new XAttribute( w + "val", "99" ) ),
  2822. new XElement( w + "unhideWhenUsed" ),
  2823. new XElement( w + "rsid", new XAttribute( w + "val", "0005416C" ) ),
  2824. new XElement
  2825. (
  2826. w + "rPr",
  2827. new XElement( w + "color", new XAttribute( w + "val", "0000FF" ), new XAttribute( w + "themeColor", "hyperlink" ) ),
  2828. new XElement
  2829. (
  2830. w + "u",
  2831. new XAttribute( w + "val", "single" )
  2832. )
  2833. )
  2834. );
  2835. word_styles.Element( w + "styles" ).Add( style );
  2836. // Save the styles document.
  2837. using( TextWriter tw = new StreamWriter( new PackagePartStream( _package.GetPart( word_styles_Uri ).GetStream() ) ) )
  2838. {
  2839. word_styles.Save( tw );
  2840. }
  2841. }
  2842. }
  2843. /// <summary>
  2844. /// Adds a Header to a document.
  2845. /// If the document already contains a Header it will be replaced.
  2846. /// </summary>
  2847. /// <returns>The Header that was added to the document.</returns>
  2848. internal void AddHeadersOrFooters( bool b )
  2849. {
  2850. var element = b ? "hdr" : "ftr";
  2851. var reference = b ? "header" : "footer";
  2852. this.DeleteHeadersOrFooters( b );
  2853. var sectPr = _mainDoc.Root.Element( w + "body" ).Element( w + "sectPr" );
  2854. for( int i = 1; i < 4; i++ )
  2855. {
  2856. var header_uri = string.Format( "/word/{0}{1}.xml", reference, i );
  2857. var headerPart = _package.CreatePart( new Uri( header_uri, UriKind.Relative ), string.Format( "application/vnd.openxmlformats-officedocument.wordprocessingml.{0}+xml", reference ), CompressionOption.Normal );
  2858. var headerRelationship = this.PackagePart.CreateRelationship( headerPart.Uri, TargetMode.Internal, string.Format( "http://schemas.openxmlformats.org/officeDocument/2006/relationships/{0}", reference ) );
  2859. XDocument header;
  2860. // Load the document part into a XDocument object
  2861. using( TextReader tr = new StreamReader( headerPart.GetStream( FileMode.Create, FileAccess.ReadWrite ) ) )
  2862. {
  2863. header = XDocument.Parse
  2864. ( string.Format( @"<?xml version=""1.0"" encoding=""utf-16"" standalone=""yes""?>
  2865. <w:{0} xmlns:ve=""http://schemas.openxmlformats.org/markup-compatibility/2006"" 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:wp=""http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing"" xmlns:w10=""urn:schemas-microsoft-com:office:word"" xmlns:w=""http://schemas.openxmlformats.org/wordprocessingml/2006/main"" xmlns:wne=""http://schemas.microsoft.com/office/word/2006/wordml"">
  2866. <w:p w:rsidR=""009D472B"" w:rsidRDefault=""009D472B"">
  2867. <w:pPr>
  2868. <w:pStyle w:val=""{1}"" />
  2869. </w:pPr>
  2870. </w:p>
  2871. </w:{0}>", element, reference )
  2872. );
  2873. }
  2874. // Save the main document
  2875. using( TextWriter tw = new StreamWriter( new PackagePartStream( headerPart.GetStream( FileMode.Create, FileAccess.Write ) ) ) )
  2876. {
  2877. header.Save( tw, SaveOptions.None );
  2878. }
  2879. string type;
  2880. switch( i )
  2881. {
  2882. case 1:
  2883. type = "default";
  2884. break;
  2885. case 2:
  2886. type = "even";
  2887. break;
  2888. case 3:
  2889. type = "first";
  2890. break;
  2891. default:
  2892. throw new ArgumentOutOfRangeException();
  2893. }
  2894. sectPr.Add
  2895. (
  2896. new XElement
  2897. (
  2898. w + string.Format( "{0}Reference", reference ),
  2899. new XAttribute( w + "type", type ),
  2900. new XAttribute( r + "id", headerRelationship.Id )
  2901. )
  2902. );
  2903. }
  2904. }
  2905. internal void DeleteHeadersOrFooters( bool b )
  2906. {
  2907. string reference = "footer";
  2908. if( b )
  2909. reference = "header";
  2910. // Get all header Relationships in this document.
  2911. var header_relationships = this.PackagePart.GetRelationshipsByType( string.Format( "http://schemas.openxmlformats.org/officeDocument/2006/relationships/{0}", reference ) );
  2912. foreach( PackageRelationship header_relationship in header_relationships )
  2913. {
  2914. // Get the TargetUri for this Part.
  2915. Uri header_uri = header_relationship.TargetUri;
  2916. // Check to see if the document actually contains the Part.
  2917. if( !header_uri.OriginalString.StartsWith( "/word/" ) )
  2918. header_uri = new Uri( "/word/" + header_uri.OriginalString, UriKind.Relative );
  2919. if( _package.PartExists( header_uri ) )
  2920. {
  2921. // Delete the Part
  2922. _package.DeletePart( header_uri );
  2923. // Get all references to this Relationship in the document.
  2924. var query =
  2925. (
  2926. from e in _mainDoc.Descendants( XName.Get( "body", w.NamespaceName ) ).Descendants()
  2927. where ( e.Name.LocalName == string.Format( "{0}Reference", reference ) ) && ( e.Attribute( r + "id" ).Value == header_relationship.Id )
  2928. select e
  2929. );
  2930. // Remove all references to this Relationship in the document.
  2931. for( int i = 0; i < query.Count(); i++ )
  2932. query.ElementAt( i ).Remove();
  2933. // Delete the Relationship.
  2934. _package.DeleteRelationship( header_relationship.Id );
  2935. }
  2936. }
  2937. }
  2938. internal Image AddImage( object o, string contentType = "image/jpeg" )
  2939. {
  2940. // Open a Stream to the new image being added.
  2941. var newImageStream = ( o is string ) ? new FileStream( o as string, FileMode.Open, FileAccess.Read ) : o as Stream;
  2942. // Get all image parts in word\document.xml
  2943. PackagePartCollection packagePartCollection = _package.GetParts();
  2944. var parts = packagePartCollection.Select( x => new
  2945. {
  2946. UriString = x.Uri.ToString(),
  2947. Part = x
  2948. } ).ToList();
  2949. var partLookup = parts.ToDictionary( x => x.UriString, x => x.Part, StringComparer.Ordinal );
  2950. List<PackagePart> imageParts = new List<PackagePart>();
  2951. foreach( var item in this.PackagePart.GetRelationshipsByType( RelationshipImage ) )
  2952. {
  2953. var targetUri = item.TargetUri.ToString();
  2954. PackagePart part;
  2955. if( partLookup.TryGetValue( targetUri, out part ) )
  2956. {
  2957. imageParts.Add( part );
  2958. }
  2959. }
  2960. IEnumerable<PackagePart> relsParts = parts
  2961. .Where(
  2962. part =>
  2963. part.Part.ContentType.Equals( ContentTypeApplicationRelationShipXml, StringComparison.Ordinal ) &&
  2964. part.UriString.IndexOf( "/word/", StringComparison.Ordinal ) > -1 )
  2965. .Select( part => part.Part );
  2966. XName xNameTarget = XName.Get( "Target" );
  2967. XName xNameTargetMode = XName.Get( "TargetMode" );
  2968. foreach( PackagePart relsPart in relsParts )
  2969. {
  2970. XDocument relsPartContent;
  2971. using( TextReader tr = new StreamReader( relsPart.GetStream( FileMode.Open, FileAccess.Read ) ) )
  2972. {
  2973. relsPartContent = XDocument.Load( tr );
  2974. }
  2975. var imageRelationships =
  2976. relsPartContent.Root.Elements().Where
  2977. (
  2978. imageRel =>
  2979. imageRel.Attribute( XName.Get( "Type" ) ).Value.Equals( "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image" )
  2980. );
  2981. foreach( XElement imageRelationship in imageRelationships )
  2982. {
  2983. XAttribute attribute = imageRelationship.Attribute( xNameTarget );
  2984. if( attribute != null )
  2985. {
  2986. var targetModeAttr = imageRelationship.Attribute( xNameTargetMode );
  2987. var targetMode = ( targetModeAttr != null ) ? targetModeAttr.Value : string.Empty;
  2988. if( !targetMode.Equals( "External" ) )
  2989. {
  2990. var imagePartUri = Path.Combine( Path.GetDirectoryName( relsPart.Uri.ToString() ), attribute.Value );
  2991. imagePartUri = Path.GetFullPath( imagePartUri.Replace( "\\_rels", string.Empty ) );
  2992. imagePartUri = imagePartUri.Replace( Path.GetFullPath( "\\" ), string.Empty ).Replace( "\\", "/" );
  2993. if( !imagePartUri.StartsWith( "/" ) )
  2994. {
  2995. imagePartUri = "/" + imagePartUri;
  2996. }
  2997. var imagePart = _package.GetPart( new Uri( imagePartUri, UriKind.Relative ) );
  2998. imageParts.Add( imagePart );
  2999. }
  3000. }
  3001. }
  3002. }
  3003. // Loop through each image part in this document.
  3004. foreach( PackagePart pp in imageParts )
  3005. {
  3006. // Get the image object for this image part.
  3007. using( Stream tempStream = pp.GetStream( FileMode.Open, FileAccess.Read ) )
  3008. {
  3009. // Compare this image to the new image being added.
  3010. if( HelperFunctions.IsSameFile( tempStream, newImageStream ) )
  3011. {
  3012. // Return the Image object
  3013. PackageRelationship relationship = this.PackagePart.GetRelationshipsByType( RelationshipImage ).First( x => x.TargetUri == pp.Uri );
  3014. return new Image( this, relationship );
  3015. }
  3016. }
  3017. }
  3018. var imgPartUriPath = string.Empty;
  3019. var extension = contentType.Substring( contentType.LastIndexOf( "/" ) + 1 );
  3020. do
  3021. {
  3022. // Create a new image part.
  3023. imgPartUriPath = string.Format
  3024. (
  3025. "/word/media/{0}.{1}",
  3026. Guid.NewGuid(), // The unique part.
  3027. extension
  3028. );
  3029. } while( _package.PartExists( new Uri( imgPartUriPath, UriKind.Relative ) ) );
  3030. // We are now guaranteed that imgPartUriPath is unique.
  3031. var img = _package.CreatePart( new Uri( imgPartUriPath, UriKind.Relative ), contentType, CompressionOption.Normal );
  3032. // Create a new image relationship
  3033. var rel = this.PackagePart.CreateRelationship( img.Uri, TargetMode.Internal, RelationshipImage );
  3034. // Open a Stream to the newly created Image part.
  3035. using( Stream stream = new PackagePartStream( img.GetStream( FileMode.Create, FileAccess.Write ) ) )
  3036. {
  3037. // Using the Stream to the real image, copy this streams data into the newly create Image part.
  3038. using( newImageStream )
  3039. {
  3040. CopyStream( newImageStream, stream, bufferSize: 4096 );
  3041. }// Close the Stream to the new image.
  3042. }// Close the Stream to the new image part.
  3043. return new Image( this, rel );
  3044. }
  3045. internal static void UpdateCorePropertyValue( DocX document, string corePropertyName, string corePropertyValue )
  3046. {
  3047. var matchPattern = string.Format( @"(DOCPROPERTY)?{0}\\\*MERGEFORMAT", corePropertyName ).ToLower();
  3048. foreach( XElement e in document._mainDoc.Descendants( XName.Get( "fldSimple", w.NamespaceName ) ) )
  3049. {
  3050. var attr_value = e.Attribute( XName.Get( "instr", w.NamespaceName ) ).Value.Replace( " ", string.Empty ).Trim().ToLower();
  3051. if( Regex.IsMatch( attr_value, matchPattern ) )
  3052. {
  3053. var firstRun = e.Element( w + "r" );
  3054. var firstText = firstRun.Element( w + "t" );
  3055. var rPr = firstText.Element( w + "rPr" );
  3056. // Delete everything and insert updated text value
  3057. e.RemoveNodes();
  3058. var t = new XElement( w + "t", rPr, corePropertyValue );
  3059. Xceed.Words.NET.Text.PreserveSpace( t );
  3060. e.Add( new XElement( firstRun.Name, firstRun.Attributes(), firstRun.Element( XName.Get( "rPr", w.NamespaceName ) ), t ) );
  3061. }
  3062. }
  3063. #region Headers
  3064. var headerParts = from headerPart in document._package.GetParts()
  3065. where ( Regex.IsMatch( headerPart.Uri.ToString(), @"/word/header\d?.xml" ) )
  3066. select headerPart;
  3067. foreach( PackagePart pp in headerParts )
  3068. {
  3069. var header = XDocument.Load( new StreamReader( pp.GetStream() ) );
  3070. foreach( XElement e in header.Descendants( XName.Get( "fldSimple", w.NamespaceName ) ) )
  3071. {
  3072. string attr_value = e.Attribute( XName.Get( "instr", w.NamespaceName ) ).Value.Replace( " ", string.Empty ).Trim().ToLower();
  3073. if( Regex.IsMatch( attr_value, matchPattern ) )
  3074. {
  3075. var firstRun = e.Element( w + "r" );
  3076. // Delete everything and insert updated text value
  3077. e.RemoveNodes();
  3078. var t = new XElement( w + "t", corePropertyValue );
  3079. Xceed.Words.NET.Text.PreserveSpace( t );
  3080. e.Add( new XElement( firstRun.Name, firstRun.Attributes(), firstRun.Element( XName.Get( "rPr", w.NamespaceName ) ), t ) );
  3081. }
  3082. }
  3083. using( TextWriter tw = new StreamWriter( new PackagePartStream( pp.GetStream( FileMode.Create, FileAccess.Write ) ) ) )
  3084. {
  3085. header.Save( tw );
  3086. }
  3087. }
  3088. #endregion
  3089. #region Footers
  3090. var footerParts = from footerPart in document._package.GetParts()
  3091. where ( Regex.IsMatch( footerPart.Uri.ToString(), @"/word/footer\d?.xml" ) )
  3092. select footerPart;
  3093. foreach( PackagePart pp in footerParts )
  3094. {
  3095. var footer = XDocument.Load( new StreamReader( pp.GetStream() ) );
  3096. foreach( XElement e in footer.Descendants( XName.Get( "fldSimple", w.NamespaceName ) ) )
  3097. {
  3098. string attr_value = e.Attribute( XName.Get( "instr", w.NamespaceName ) ).Value.Replace( " ", string.Empty ).Trim().ToLower();
  3099. if( Regex.IsMatch( attr_value, matchPattern ) )
  3100. {
  3101. var firstRun = e.Element( w + "r" );
  3102. // Delete everything and insert updated text value
  3103. e.RemoveNodes();
  3104. var t = new XElement( w + "t", corePropertyValue );
  3105. Xceed.Words.NET.Text.PreserveSpace( t );
  3106. e.Add( new XElement( firstRun.Name, firstRun.Attributes(), firstRun.Element( XName.Get( "rPr", w.NamespaceName ) ), t ) );
  3107. }
  3108. }
  3109. using( TextWriter tw = new StreamWriter( new PackagePartStream( pp.GetStream( FileMode.Create, FileAccess.Write ) ) ) )
  3110. {
  3111. footer.Save( tw );
  3112. }
  3113. }
  3114. #endregion
  3115. DocX.PopulateDocument( document, document._package );
  3116. }
  3117. /// <summary>
  3118. /// Update the custom properties inside the document
  3119. /// </summary>
  3120. /// <param name="document">The DocX document</param>
  3121. /// <param name="customPropertyName">The property used inside the document</param>
  3122. /// <param name="customPropertyValue">The new value for the property</param>
  3123. /// <remarks>Different version of Word create different Document XML.</remarks>
  3124. internal static void UpdateCustomPropertyValue( DocX document, string customPropertyName, string customPropertyValue )
  3125. {
  3126. // A list of documents, which will contain, The Main Document and if they exist: header1, header2, header3, footer1, footer2, footer3.
  3127. var documents = new List<XElement> { document._mainDoc.Root };
  3128. // Check if each header exists and add if if so.
  3129. #region Headers
  3130. var headers = document.Headers;
  3131. if( headers.First != null )
  3132. {
  3133. documents.Add( headers.First.Xml );
  3134. }
  3135. if( headers.Odd != null )
  3136. {
  3137. documents.Add( headers.Odd.Xml );
  3138. }
  3139. if( headers.Even != null )
  3140. {
  3141. documents.Add( headers.Even.Xml );
  3142. }
  3143. #endregion
  3144. // Check if each footer exists and add if if so.
  3145. #region Footers
  3146. var footers = document.Footers;
  3147. if( footers.First != null )
  3148. {
  3149. documents.Add( footers.First.Xml );
  3150. }
  3151. if( footers.Odd != null )
  3152. {
  3153. documents.Add( footers.Odd.Xml );
  3154. }
  3155. if( footers.Even != null )
  3156. {
  3157. documents.Add( footers.Even.Xml );
  3158. }
  3159. #endregion
  3160. var match_value = string.Format( @"DOCPROPERTY {0} \* MERGEFORMAT", customPropertyName.Contains( " " ) ? "\"" + customPropertyName + "\"" : customPropertyName )
  3161. .Replace( " ", string.Empty );
  3162. // Process each document in the list.
  3163. foreach( XElement doc in documents )
  3164. {
  3165. #region Word 2010+
  3166. foreach( XElement e in doc.Descendants( XName.Get( "instrText", w.NamespaceName ) ) )
  3167. {
  3168. var attr_value = e.Value.Replace( " ", string.Empty ).Trim();
  3169. if( attr_value.Equals( match_value, StringComparison.CurrentCultureIgnoreCase ) )
  3170. {
  3171. var node = e.Parent.NextNode;
  3172. bool found = false;
  3173. while( true )
  3174. {
  3175. if( node.NodeType == XmlNodeType.Element )
  3176. {
  3177. var ele = node as XElement;
  3178. var match = ele.Descendants( XName.Get( "t", w.NamespaceName ) );
  3179. if( match.Any() )
  3180. {
  3181. if( !found )
  3182. {
  3183. match.First().Value = customPropertyValue;
  3184. found = true;
  3185. }
  3186. else
  3187. {
  3188. ele.RemoveNodes();
  3189. }
  3190. }
  3191. else
  3192. {
  3193. match = ele.Descendants( XName.Get( "fldChar", w.NamespaceName ) );
  3194. if( match.Any() )
  3195. {
  3196. var endMatch = match.First().Attribute( XName.Get( "fldCharType", w.NamespaceName ) );
  3197. if( endMatch != null && endMatch.Value == "end" )
  3198. {
  3199. break;
  3200. }
  3201. }
  3202. }
  3203. }
  3204. node = node.NextNode;
  3205. }
  3206. }
  3207. }
  3208. #endregion
  3209. #region < Word 2010
  3210. foreach( XElement e in doc.Descendants( XName.Get( "fldSimple", w.NamespaceName ) ) )
  3211. {
  3212. var attr_value = e.Attribute( XName.Get( "instr", w.NamespaceName ) ).Value.Replace( " ", string.Empty ).Trim();
  3213. if( attr_value.Equals( match_value, StringComparison.CurrentCultureIgnoreCase ) )
  3214. {
  3215. var firstRun = e.Element( w + "r" );
  3216. var firstText = firstRun.Element( w + "t" );
  3217. var rPr = firstText.Element( w + "rPr" );
  3218. // Delete everything and insert updated text value
  3219. e.RemoveNodes();
  3220. var t = new XElement( w + "t", rPr, customPropertyValue );
  3221. Xceed.Words.NET.Text.PreserveSpace( t );
  3222. e.Add( new XElement( firstRun.Name, firstRun.Attributes(), firstRun.Element( XName.Get( "rPr", w.NamespaceName ) ), t ) );
  3223. }
  3224. }
  3225. #endregion
  3226. }
  3227. }
  3228. internal XDocument AddStylesForList()
  3229. {
  3230. var fileUri = new Uri( "/word/styles.xml", UriKind.Relative );
  3231. // Create the /word/styles.xml if it doesn't already exist
  3232. if( !_package.PartExists( fileUri ) )
  3233. HelperFunctions.AddDefaultStylesXml( _package );
  3234. // Load the xml into memory.
  3235. XDocument stylesDoc;
  3236. using( TextReader tr = new StreamReader( _package.GetPart( fileUri ).GetStream() ) )
  3237. stylesDoc = XDocument.Load( tr );
  3238. bool listStyleExists =
  3239. (
  3240. from s in stylesDoc.Element( w + "styles" ).Elements()
  3241. let styleId = s.Attribute( XName.Get( "styleId", w.NamespaceName ) )
  3242. where ( styleId != null && styleId.Value == "ListParagraph" )
  3243. select s
  3244. ).Any();
  3245. if( !listStyleExists )
  3246. {
  3247. var style = new XElement
  3248. (
  3249. w + "style",
  3250. new XAttribute( w + "type", "paragraph" ),
  3251. new XAttribute( w + "styleId", "ListParagraph" ),
  3252. new XElement( w + "name", new XAttribute( w + "val", "List Paragraph" ) ),
  3253. new XElement( w + "basedOn", new XAttribute( w + "val", "Normal" ) ),
  3254. new XElement( w + "uiPriority", new XAttribute( w + "val", "34" ) ),
  3255. new XElement( w + "qformat" ),
  3256. new XElement( w + "rsid", new XAttribute( w + "val", "00832EE1" ) ),
  3257. new XElement
  3258. (
  3259. w + "rPr",
  3260. new XElement( w + "ind", new XAttribute( w + "left", "720" ) ),
  3261. new XElement
  3262. (
  3263. w + "contextualSpacing"
  3264. )
  3265. )
  3266. );
  3267. stylesDoc.Element( w + "styles" ).Add( style );
  3268. // Save the document
  3269. using( TextWriter tw = new StreamWriter( _package.GetPart( fileUri ).GetStream() ) )
  3270. stylesDoc.Save( tw );
  3271. }
  3272. return stylesDoc;
  3273. }
  3274. internal bool getMirrorMargins(XName name)
  3275. {
  3276. var body = _mainDoc.Root.Element(XName.Get("body", DocX.w.NamespaceName));
  3277. var sectPr = body.Element(XName.Get("sectPr", DocX.w.NamespaceName));
  3278. var mirrorMargins = sectPr?.Element(XName.Get("mirrorMargins", DocX.w.NamespaceName));
  3279. return (mirrorMargins != null);
  3280. }
  3281. internal void setMirrorMargins(XName name, bool value)
  3282. {
  3283. var body = _mainDoc.Root.Element(XName.Get("body", DocX.w.NamespaceName));
  3284. var sectPr = body.Element(XName.Get("sectPr", DocX.w.NamespaceName));
  3285. var mirrorMargins = sectPr?.Element(XName.Get("mirrorMargins", DocX.w.NamespaceName));
  3286. if (mirrorMargins == null)
  3287. sectPr.Add(new XElement(w + "mirrorMargins", string.Empty));
  3288. else
  3289. {
  3290. if (!value)
  3291. mirrorMargins.Remove();
  3292. }
  3293. }
  3294. /// <summary>
  3295. /// Finds the next free Id for bookmarkStart/docPr.
  3296. /// </summary>
  3297. internal long GetNextFreeDocPrId()
  3298. {
  3299. lock( nextFreeDocPrIdLock )
  3300. {
  3301. if( nextFreeDocPrId != null )
  3302. {
  3303. nextFreeDocPrId++;
  3304. return nextFreeDocPrId.Value;
  3305. }
  3306. var xNameBookmarkStart = XName.Get( "bookmarkStart", DocX.w.NamespaceName );
  3307. var xNameDocPr = XName.Get( "docPr", DocX.wp.NamespaceName );
  3308. long newDocPrId = 1;
  3309. HashSet<string> existingIds = new HashSet<string>();
  3310. foreach( var bookmarkId in Xml.Descendants() )
  3311. {
  3312. if( bookmarkId.Name != xNameBookmarkStart && bookmarkId.Name != xNameDocPr )
  3313. continue;
  3314. var idAtt = bookmarkId.Attributes().FirstOrDefault( x => x.Name.LocalName == "id" );
  3315. if( idAtt != null )
  3316. existingIds.Add( idAtt.Value );
  3317. }
  3318. while( existingIds.Contains( newDocPrId.ToString() ) )
  3319. newDocPrId++;
  3320. nextFreeDocPrId = newDocPrId;
  3321. return nextFreeDocPrId.Value;
  3322. }
  3323. }
  3324. #endregion
  3325. #region Private Methods
  3326. private static DocX CreateDocument( DocumentTypes documentType )
  3327. {
  3328. // Store this document in memory
  3329. var ms = new MemoryStream();
  3330. // Create the docx package
  3331. var package = Package.Open( ms, FileMode.Create, FileAccess.ReadWrite );
  3332. DocX.PostCreation( package, documentType );
  3333. return DocX.Load( ms );
  3334. }
  3335. private Header GetHeaderByType( string type )
  3336. {
  3337. return ( Header )GetHeaderOrFooterByType( type, true );
  3338. }
  3339. private Footer GetFooterByType( string type )
  3340. {
  3341. return ( Footer )GetHeaderOrFooterByType( type, false );
  3342. }
  3343. private object GetHeaderOrFooterByType( string type, bool isHeader )
  3344. {
  3345. // Switch which handles either case Header\Footer, this just cuts down on code duplication.
  3346. string reference = "footerReference";
  3347. if( isHeader )
  3348. reference = "headerReference";
  3349. // Get the Id of the [default, even or first] [Header or Footer]
  3350. string Id =
  3351. (
  3352. from e in _mainDoc.Descendants( XName.Get( "body", w.NamespaceName ) ).Descendants()
  3353. where ( e.Name.LocalName == reference ) && ( e.Attribute( w + "type" ).Value == type )
  3354. select e.Attribute( r + "id" ).Value
  3355. ).LastOrDefault();
  3356. if( Id != null )
  3357. {
  3358. // Get the Xml file for this Header or Footer.
  3359. var partUri = this.PackagePart.GetRelationship( Id ).TargetUri;
  3360. // Weird problem with PackaePart API.
  3361. if( !partUri.OriginalString.StartsWith( "/word/" ) )
  3362. partUri = new Uri( "/word/" + partUri.OriginalString, UriKind.Relative );
  3363. // Get the Part and open a stream to get the Xml file.
  3364. var part = _package.GetPart( partUri );
  3365. using( TextReader tr = new StreamReader( part.GetStream() ) )
  3366. {
  3367. var doc = XDocument.Load( tr );
  3368. // Header and Footer extend Container.
  3369. Container c;
  3370. if( isHeader )
  3371. {
  3372. c = new Header( this, doc.Element( w + "hdr" ), part );
  3373. }
  3374. else
  3375. {
  3376. c = new Footer( this, doc.Element( w + "ftr" ), part );
  3377. }
  3378. return c;
  3379. }
  3380. }
  3381. // If we got this far something went wrong.
  3382. return null;
  3383. }
  3384. private void merge_images( PackagePart remote_pp, DocX remote_document, XDocument remote_mainDoc, String contentType )
  3385. {
  3386. // Before doing any other work, check to see if this image is actually referenced in the document.
  3387. // In my testing I have found cases of Images inside documents that are not referenced
  3388. var remote_rel = remote_document.PackagePart.GetRelationships().Where( r => r.TargetUri.OriginalString.Equals( remote_pp.Uri.OriginalString.Replace( "/word/", "" ) ) ).FirstOrDefault();
  3389. if( remote_rel == null )
  3390. {
  3391. remote_rel = remote_document.PackagePart.GetRelationships().Where( r => r.TargetUri.OriginalString.Equals( remote_pp.Uri.OriginalString ) ).FirstOrDefault();
  3392. if( remote_rel == null )
  3393. return;
  3394. }
  3395. var remote_Id = remote_rel.Id;
  3396. var remote_hash = this.ComputeMD5HashString( remote_pp.GetStream() );
  3397. var image_parts = _package.GetParts().Where( pp => pp.ContentType.Equals( contentType ) );
  3398. bool found = false;
  3399. foreach( var part in image_parts )
  3400. {
  3401. var local_hash = ComputeMD5HashString( part.GetStream() );
  3402. if( local_hash.Equals( remote_hash ) )
  3403. {
  3404. // This image already exists in this document.
  3405. found = true;
  3406. var local_rel = this.PackagePart.GetRelationships().Where( r => r.TargetUri.OriginalString.Equals( part.Uri.OriginalString.Replace( "/word/", "" ) ) ).FirstOrDefault();
  3407. if( local_rel == null )
  3408. {
  3409. local_rel = this.PackagePart.GetRelationships().Where( r => r.TargetUri.OriginalString.Equals( part.Uri.OriginalString ) ).FirstOrDefault();
  3410. }
  3411. if( local_rel != null )
  3412. {
  3413. var new_Id = local_rel.Id;
  3414. // Replace all instances of remote_Id in the local document with local_Id
  3415. this.ReplaceAllRemoteID( remote_mainDoc, "blip", "embed", a.NamespaceName, remote_Id, new_Id );
  3416. // Replace all instances of remote_Id in the local document with local_Id (for shapes)
  3417. this.ReplaceAllRemoteID( remote_mainDoc, "imagedata", "id", v.NamespaceName, remote_Id, new_Id );
  3418. }
  3419. break;
  3420. }
  3421. }
  3422. // This image does not exist in this document.
  3423. if( !found )
  3424. {
  3425. var new_uri = remote_pp.Uri.OriginalString;
  3426. new_uri = new_uri.Remove( new_uri.LastIndexOf( "/" ) );
  3427. new_uri += "/" + Guid.NewGuid() + contentType.Replace( "image/", "." );
  3428. if( !new_uri.StartsWith( "/" ) )
  3429. {
  3430. new_uri = "/" + new_uri;
  3431. }
  3432. var new_pp = _package.CreatePart( new Uri( new_uri, UriKind.Relative ), remote_pp.ContentType, CompressionOption.Normal );
  3433. using( Stream s_read = remote_pp.GetStream() )
  3434. {
  3435. using( Stream s_write = new PackagePartStream( new_pp.GetStream( FileMode.Create ) ) )
  3436. {
  3437. CopyStream( s_read, s_write );
  3438. }
  3439. }
  3440. var pr = this.PackagePart.CreateRelationship( new Uri( new_uri, UriKind.Relative ), TargetMode.Internal, RelationshipImage );
  3441. var new_Id = pr.Id;
  3442. //Check if the remote relationship id is a default rId from Word
  3443. Match relationshipID = Regex.Match( remote_Id, @"rId\d+", RegexOptions.IgnoreCase );
  3444. // Replace all instances of remote_Id in the local document with local_Id
  3445. this.ReplaceAllRemoteID( remote_mainDoc, "blip", "embed", a.NamespaceName, remote_Id, new_Id );
  3446. if( !relationshipID.Success )
  3447. {
  3448. // Replace all instances of remote_Id in the local document with local_Id
  3449. this.ReplaceAllRemoteID( _mainDoc, "blip", "embed", a.NamespaceName, remote_Id, new_Id );
  3450. // Replace all instances of remote_Id in the local document with local_Id (for shapes)
  3451. this.ReplaceAllRemoteID( _mainDoc, "imagedata", "id", v.NamespaceName, remote_Id, new_Id );
  3452. }
  3453. // Replace all instances of remote_Id in the local document with local_Id (for shapes)
  3454. this.ReplaceAllRemoteID( remote_mainDoc, "imagedata", "id", v.NamespaceName, remote_Id, new_Id );
  3455. }
  3456. }
  3457. private void ReplaceAllRemoteID( XDocument remote_mainDoc, string localName, string localNameAttribute, string namespaceName, string remote_Id, string new_Id )
  3458. {
  3459. // Replace all instances of remote_Id in the local document with local_Id
  3460. var elems = remote_mainDoc.Descendants( XName.Get( localName, namespaceName ) );
  3461. foreach( var elem in elems )
  3462. {
  3463. var attribute = elem.Attribute( XName.Get( localNameAttribute, DocX.r.NamespaceName ) );
  3464. if( attribute != null && attribute.Value == remote_Id )
  3465. {
  3466. attribute.SetValue( new_Id );
  3467. }
  3468. }
  3469. }
  3470. private string ComputeMD5HashString( Stream stream )
  3471. {
  3472. MD5 md5 = MD5.Create();
  3473. byte[] hash = md5.ComputeHash( stream );
  3474. StringBuilder sb = new StringBuilder();
  3475. foreach( byte b in hash )
  3476. sb.Append( b.ToString( "X2" ) );
  3477. return sb.ToString();
  3478. }
  3479. private void merge_endnotes( PackagePart remote_pp, PackagePart local_pp, XDocument remote_mainDoc, DocX remote, XDocument remote_endnotes )
  3480. {
  3481. IEnumerable<int> ids =
  3482. (
  3483. from d in _endnotes.Root.Descendants()
  3484. where d.Name.LocalName == "endnote"
  3485. select int.Parse( d.Attribute( XName.Get( "id", w.NamespaceName ) ).Value )
  3486. );
  3487. int max_id = ids.Max() + 1;
  3488. var endnoteReferences = remote_mainDoc.Descendants( XName.Get( "endnoteReference", w.NamespaceName ) );
  3489. foreach( var endnote in remote_endnotes.Root.Elements().OrderBy( fr => fr.Attribute( XName.Get( "id", r.NamespaceName ) ) ).Reverse() )
  3490. {
  3491. XAttribute id = endnote.Attribute( XName.Get( "id", w.NamespaceName ) );
  3492. int i;
  3493. if( id != null && int.TryParse( id.Value, out i ) )
  3494. {
  3495. if( i > 0 )
  3496. {
  3497. foreach( var endnoteRef in endnoteReferences )
  3498. {
  3499. XAttribute a = endnoteRef.Attribute( XName.Get( "id", w.NamespaceName ) );
  3500. if( a != null && int.Parse( a.Value ).Equals( i ) )
  3501. {
  3502. a.SetValue( max_id );
  3503. }
  3504. }
  3505. // We care about copying this footnote.
  3506. endnote.SetAttributeValue( XName.Get( "id", w.NamespaceName ), max_id );
  3507. _endnotes.Root.Add( endnote );
  3508. max_id++;
  3509. }
  3510. }
  3511. }
  3512. }
  3513. private void merge_footnotes( PackagePart remote_pp, PackagePart local_pp, XDocument remote_mainDoc, DocX remote, XDocument remote_footnotes )
  3514. {
  3515. IEnumerable<int> ids =
  3516. (
  3517. from d in _footnotes.Root.Descendants()
  3518. where d.Name.LocalName == "footnote"
  3519. select int.Parse( d.Attribute( XName.Get( "id", DocX.w.NamespaceName ) ).Value )
  3520. );
  3521. int max_id = ids.Max() + 1;
  3522. var footnoteReferences = remote_mainDoc.Descendants( XName.Get( "footnoteReference", DocX.w.NamespaceName ) );
  3523. foreach( var footnote in remote_footnotes.Root.Elements().OrderBy( fr => fr.Attribute( XName.Get( "id", DocX.r.NamespaceName ) ) ).Reverse() )
  3524. {
  3525. XAttribute id = footnote.Attribute( XName.Get( "id", DocX.w.NamespaceName ) );
  3526. int i;
  3527. if( id != null && int.TryParse( id.Value, out i ) )
  3528. {
  3529. if( i > 0 )
  3530. {
  3531. foreach( var footnoteRef in footnoteReferences )
  3532. {
  3533. XAttribute a = footnoteRef.Attribute( XName.Get( "id", DocX.w.NamespaceName ) );
  3534. if( a != null && int.Parse( a.Value ).Equals( i ) )
  3535. {
  3536. a.SetValue( max_id );
  3537. }
  3538. }
  3539. // We care about copying this footnote.
  3540. footnote.SetAttributeValue( XName.Get( "id", DocX.w.NamespaceName ), max_id );
  3541. _footnotes.Root.Add( footnote );
  3542. max_id++;
  3543. }
  3544. }
  3545. }
  3546. }
  3547. private void merge_customs( PackagePart remote_pp, PackagePart local_pp, XDocument remote_mainDoc )
  3548. {
  3549. // Get the remote documents custom.xml file.
  3550. XDocument remote_custom_document;
  3551. using( TextReader tr = new StreamReader( remote_pp.GetStream() ) )
  3552. {
  3553. remote_custom_document = XDocument.Load( tr );
  3554. }
  3555. // Get the local documents custom.xml file.
  3556. XDocument local_custom_document;
  3557. using( TextReader tr = new StreamReader( local_pp.GetStream() ) )
  3558. {
  3559. local_custom_document = XDocument.Load( tr );
  3560. }
  3561. IEnumerable<int> pids =
  3562. (
  3563. from d in remote_custom_document.Root.Descendants()
  3564. where d.Name.LocalName == "property"
  3565. select int.Parse( d.Attribute( XName.Get( "pid" ) ).Value )
  3566. );
  3567. int pid = pids.Max() + 1;
  3568. foreach( XElement remote_property in remote_custom_document.Root.Elements() )
  3569. {
  3570. bool found = false;
  3571. foreach( XElement local_property in local_custom_document.Root.Elements() )
  3572. {
  3573. var remote_property_name = remote_property.Attribute( XName.Get( "name" ) );
  3574. var local_property_name = local_property.Attribute( XName.Get( "name" ) );
  3575. if( remote_property != null && local_property_name != null && remote_property_name.Value.Equals( local_property_name.Value ) )
  3576. {
  3577. found = true;
  3578. }
  3579. }
  3580. if( !found )
  3581. {
  3582. remote_property.SetAttributeValue( XName.Get( "pid" ), pid );
  3583. local_custom_document.Root.Add( remote_property );
  3584. pid++;
  3585. }
  3586. }
  3587. // Save the modified local custom styles.xml file.
  3588. using( TextWriter tw = new StreamWriter( new PackagePartStream( local_pp.GetStream( FileMode.Create, FileAccess.Write ) ) ) )
  3589. {
  3590. local_custom_document.Save( tw, SaveOptions.None );
  3591. }
  3592. }
  3593. private void merge_numbering( PackagePart remote_pp, PackagePart local_pp, XDocument remote_mainDoc, DocX remote )
  3594. {
  3595. // Add each remote numbering to this document.
  3596. var abstractNumElement = _numbering.Root.Elements( XName.Get( "abstractNum", w.NamespaceName ) );
  3597. var remote_abstractNums = remote._numbering.Root.Elements( XName.Get( "abstractNum", w.NamespaceName ) );
  3598. int guidd = -1;
  3599. foreach( var an in abstractNumElement )
  3600. {
  3601. var a = an.Attribute( XName.Get( "abstractNumId", w.NamespaceName ) );
  3602. if( a != null )
  3603. {
  3604. int i;
  3605. if( int.TryParse( a.Value, out i ) )
  3606. {
  3607. if( i > guidd )
  3608. {
  3609. guidd = i;
  3610. }
  3611. }
  3612. }
  3613. }
  3614. guidd++;
  3615. var remote_nums = remote._numbering.Root.Elements( XName.Get( "num", w.NamespaceName ) );
  3616. var numElement = _numbering.Root.Elements( XName.Get( "num", w.NamespaceName ) );
  3617. int guidd2 = 0;
  3618. foreach( var an in numElement )
  3619. {
  3620. var a = an.Attribute( XName.Get( "numId", w.NamespaceName ) );
  3621. if( a != null )
  3622. {
  3623. int i;
  3624. if( int.TryParse( a.Value, out i ) )
  3625. {
  3626. if( i > guidd2 )
  3627. {
  3628. guidd2 = i;
  3629. }
  3630. }
  3631. }
  3632. }
  3633. guidd2++;
  3634. foreach( XElement remote_abstractNum in remote_abstractNums )
  3635. {
  3636. var currentGuidd2 = guidd2;
  3637. var abstractNumId = remote_abstractNum.Attribute( XName.Get( "abstractNumId", w.NamespaceName ) );
  3638. if( abstractNumId != null )
  3639. {
  3640. var abstractNumIdValue = abstractNumId.Value;
  3641. abstractNumId.SetValue( guidd );
  3642. foreach( XElement remote_num in remote_nums )
  3643. {
  3644. // in document
  3645. var numIds = remote_mainDoc.Descendants( XName.Get( "numId", w.NamespaceName ) );
  3646. foreach( var numId in numIds )
  3647. {
  3648. var attr = numId.Attribute( XName.Get( "val", w.NamespaceName ) );
  3649. if( attr != null && attr.Value.Equals( remote_num.Attribute( XName.Get( "numId", w.NamespaceName ) ).Value ) )
  3650. {
  3651. attr.SetValue( currentGuidd2 );
  3652. }
  3653. }
  3654. remote_num.SetAttributeValue( XName.Get( "numId", w.NamespaceName ), currentGuidd2 );
  3655. //abstractNumId of this remote_num
  3656. var e = remote_num.Element( XName.Get( "abstractNumId", w.NamespaceName ) );
  3657. var a2 = e.Attribute( XName.Get( "val", w.NamespaceName ) );
  3658. if( a2 != null && a2.Value.Equals( abstractNumIdValue ) )
  3659. a2.SetValue( guidd );
  3660. currentGuidd2++;
  3661. }
  3662. }
  3663. guidd++;
  3664. }
  3665. if( abstractNumElement != null )
  3666. {
  3667. if( abstractNumElement.Count() > 0 )
  3668. {
  3669. abstractNumElement.Last().AddAfterSelf( remote_abstractNums );
  3670. }
  3671. else
  3672. {
  3673. _numbering.Root.Add( remote_abstractNums );
  3674. }
  3675. }
  3676. if( numElement != null )
  3677. {
  3678. if( numElement.Count() > 0 )
  3679. {
  3680. numElement.Last().AddAfterSelf( remote_nums );
  3681. }
  3682. else
  3683. {
  3684. _numbering.Root.Add( remote_nums );
  3685. }
  3686. }
  3687. }
  3688. private void merge_fonts( PackagePart remote_pp, PackagePart local_pp, XDocument remote_mainDoc, DocX remote )
  3689. {
  3690. // Add each remote font to this document.
  3691. IEnumerable<XElement> remote_fonts = remote._fontTable.Root.Elements( XName.Get( "font", DocX.w.NamespaceName ) );
  3692. IEnumerable<XElement> local_fonts = _fontTable.Root.Elements( XName.Get( "font", DocX.w.NamespaceName ) );
  3693. foreach( XElement remote_font in remote_fonts )
  3694. {
  3695. bool flag_addFont = true;
  3696. foreach( XElement local_font in local_fonts )
  3697. {
  3698. if( local_font.Attribute( XName.Get( "name", DocX.w.NamespaceName ) ).Value == remote_font.Attribute( XName.Get( "name", DocX.w.NamespaceName ) ).Value )
  3699. {
  3700. flag_addFont = false;
  3701. break;
  3702. }
  3703. }
  3704. if( flag_addFont )
  3705. {
  3706. _fontTable.Root.Add( remote_font );
  3707. }
  3708. }
  3709. }
  3710. private void merge_styles( PackagePart remote_pp, PackagePart local_pp, XDocument remote_mainDoc, DocX remote, XDocument remote_footnotes, XDocument remote_endnotes )
  3711. {
  3712. var local_styles = new Dictionary<string, string>();
  3713. foreach( XElement local_style in _styles.Root.Elements( XName.Get( "style", w.NamespaceName ) ) )
  3714. {
  3715. var temp = new XElement( local_style );
  3716. var styleId = temp.Attribute( XName.Get( "styleId", w.NamespaceName ) );
  3717. var value = styleId.Value;
  3718. styleId.Remove();
  3719. var key = Regex.Replace( temp.ToString(), @"\s+", "" );
  3720. if( !local_styles.ContainsKey( key ) )
  3721. {
  3722. local_styles.Add( key, value );
  3723. }
  3724. }
  3725. // Add each remote style to this document.
  3726. var remote_styles = remote._styles.Root.Elements( XName.Get( "style", w.NamespaceName ) );
  3727. foreach( XElement remote_style in remote_styles )
  3728. {
  3729. var temp = new XElement( remote_style );
  3730. var styleId = temp.Attribute( XName.Get( "styleId", w.NamespaceName ) );
  3731. var value = styleId.Value;
  3732. styleId.Remove();
  3733. var key = Regex.Replace( temp.ToString(), @"\s+", "" );
  3734. String guuid;
  3735. // Check to see if the local document already contains the remote style.
  3736. if( local_styles.ContainsKey( key ) )
  3737. {
  3738. String local_value;
  3739. local_styles.TryGetValue( key, out local_value );
  3740. // If the styleIds are the same then nothing needs to be done.
  3741. if( local_value == value )
  3742. continue;
  3743. // All we need to do is update the styleId.
  3744. guuid = local_value;
  3745. }
  3746. else
  3747. {
  3748. guuid = Guid.NewGuid().ToString();
  3749. // Set the styleId in the remote_style to this new Guid
  3750. remote_style.SetAttributeValue( XName.Get( "styleId", w.NamespaceName ), guuid );
  3751. }
  3752. foreach( XElement e in remote_mainDoc.Root.Descendants( XName.Get( "pStyle", w.NamespaceName ) ) )
  3753. {
  3754. var e_styleId = e.Attribute( XName.Get( "val", w.NamespaceName ) );
  3755. if( ( e_styleId != null ) && e_styleId.Value.Equals( styleId.Value ) )
  3756. {
  3757. e_styleId.SetValue( guuid );
  3758. }
  3759. }
  3760. foreach( XElement e in remote_mainDoc.Root.Descendants( XName.Get( "rStyle", w.NamespaceName ) ) )
  3761. {
  3762. var e_styleId = e.Attribute( XName.Get( "val", w.NamespaceName ) );
  3763. if( ( e_styleId != null ) && e_styleId.Value.Equals( styleId.Value ) )
  3764. {
  3765. e_styleId.SetValue( guuid );
  3766. }
  3767. }
  3768. foreach( XElement e in remote_mainDoc.Root.Descendants( XName.Get( "tblStyle", w.NamespaceName ) ) )
  3769. {
  3770. var e_styleId = e.Attribute( XName.Get( "val", w.NamespaceName ) );
  3771. if( ( e_styleId != null ) && e_styleId.Value.Equals( styleId.Value ) )
  3772. {
  3773. e_styleId.SetValue( guuid );
  3774. }
  3775. }
  3776. if( remote_endnotes != null )
  3777. {
  3778. foreach( XElement e in remote_endnotes.Root.Descendants( XName.Get( "rStyle", w.NamespaceName ) ) )
  3779. {
  3780. var e_styleId = e.Attribute( XName.Get( "val", w.NamespaceName ) );
  3781. if( ( e_styleId != null ) && e_styleId.Value.Equals( styleId.Value ) )
  3782. {
  3783. e_styleId.SetValue( guuid );
  3784. }
  3785. }
  3786. foreach( XElement e in remote_endnotes.Root.Descendants( XName.Get( "pStyle", w.NamespaceName ) ) )
  3787. {
  3788. var e_styleId = e.Attribute( XName.Get( "val", w.NamespaceName ) );
  3789. if( ( e_styleId != null ) && e_styleId.Value.Equals( styleId.Value ) )
  3790. {
  3791. e_styleId.SetValue( guuid );
  3792. }
  3793. }
  3794. }
  3795. if( remote_footnotes != null )
  3796. {
  3797. foreach( XElement e in remote_footnotes.Root.Descendants( XName.Get( "rStyle", w.NamespaceName ) ) )
  3798. {
  3799. var e_styleId = e.Attribute( XName.Get( "val", w.NamespaceName ) );
  3800. if( ( e_styleId != null ) && e_styleId.Value.Equals( styleId.Value ) )
  3801. {
  3802. e_styleId.SetValue( guuid );
  3803. }
  3804. }
  3805. foreach( XElement e in remote_footnotes.Root.Descendants( XName.Get( "pStyle", w.NamespaceName ) ) )
  3806. {
  3807. var e_styleId = e.Attribute( XName.Get( "val", w.NamespaceName ) );
  3808. if( ( e_styleId != null ) && e_styleId.Value.Equals( styleId.Value ) )
  3809. {
  3810. e_styleId.SetValue( guuid );
  3811. }
  3812. }
  3813. }
  3814. // Make sure they don't clash by using a uuid.
  3815. styleId.SetValue( guuid );
  3816. _styles.Root.Add( remote_style );
  3817. }
  3818. }
  3819. protected void clonePackageRelationship( DocX remote_document, PackagePart pp, XDocument remote_mainDoc )
  3820. {
  3821. var url = pp.Uri.OriginalString.Replace( "/", "" );
  3822. var remote_rels = remote_document.PackagePart.GetRelationships();
  3823. foreach( var remote_rel in remote_rels )
  3824. {
  3825. if( url.Equals( "word" + remote_rel.TargetUri.OriginalString.Replace( "/", "" ) ) )
  3826. {
  3827. var remote_Id = remote_rel.Id;
  3828. var local_Id = this.PackagePart.CreateRelationship( remote_rel.TargetUri, remote_rel.TargetMode, remote_rel.RelationshipType ).Id;
  3829. // Replace all instances of remote_Id in the local document with local_Id
  3830. this.ReplaceAllRemoteID( remote_mainDoc, "blip", "embed", a.NamespaceName, remote_Id, local_Id );
  3831. // Replace all instances of remote_Id in the local document with local_Id (for shapes)
  3832. this.ReplaceAllRemoteID( remote_mainDoc, "imagedata", "id", v.NamespaceName, remote_Id, local_Id );
  3833. break;
  3834. }
  3835. }
  3836. }
  3837. protected PackagePart clonePackagePart( PackagePart pp )
  3838. {
  3839. var new_pp = _package.CreatePart( pp.Uri, pp.ContentType, CompressionOption.Normal );
  3840. using( Stream s_read = pp.GetStream() )
  3841. {
  3842. using( Stream s_write = new PackagePartStream( new_pp.GetStream( FileMode.Create ) ) )
  3843. {
  3844. CopyStream( s_read, s_write );
  3845. }
  3846. }
  3847. return new_pp;
  3848. }
  3849. protected string GetMD5HashFromStream( Stream stream )
  3850. {
  3851. MD5 md5 = new MD5CryptoServiceProvider();
  3852. byte[] retVal = md5.ComputeHash( stream );
  3853. StringBuilder sb = new StringBuilder();
  3854. for( int i = 0; i < retVal.Length; i++ )
  3855. {
  3856. sb.Append( retVal[ i ].ToString( "x2" ) );
  3857. }
  3858. return sb.ToString();
  3859. }
  3860. private static void PopulateDocument( DocX document, Package package )
  3861. {
  3862. var headers = new Headers();
  3863. headers.Odd = document.GetHeaderByType( "default" );
  3864. headers.Even = document.GetHeaderByType( "even" );
  3865. headers.First = document.GetHeaderByType( "first" );
  3866. var footers = new Footers();
  3867. footers.Odd = document.GetFooterByType( "default" );
  3868. footers.Even = document.GetFooterByType( "even" );
  3869. footers.First = document.GetFooterByType( "first" );
  3870. //// Get the sectPr for this document.
  3871. //XElement sectPr = document.mainDoc.Descendants(XName.Get("sectPr", DocX.w.NamespaceName)).Single();
  3872. //if (sectPr != null)
  3873. //{
  3874. // // Extract the even header reference
  3875. // var header_even_ref = sectPr.Elements().SingleOrDefault(x => x.Name.LocalName == "headerReference" && x.Attribute(XName.Get("type", DocX.w.NamespaceName)) != null && x.Attribute(XName.Get("type", DocX.w.NamespaceName)).Value == "even");
  3876. // string id = header_even_ref.Attribute(XName.Get("id", DocX.r.NamespaceName)).Value;
  3877. // var res = document.mainPart.GetRelationship(id);
  3878. // string ans = res.SourceUri.OriginalString;
  3879. // headers.even.xml_filename = ans;
  3880. // // Extract the odd header reference
  3881. // var header_odd_ref = sectPr.Elements().SingleOrDefault(x => x.Name.LocalName == "headerReference" && x.Attribute(XName.Get("type", DocX.w.NamespaceName)) != null && x.Attribute(XName.Get("type", DocX.w.NamespaceName)).Value == "default");
  3882. // string id2 = header_odd_ref.Attribute(XName.Get("id", DocX.r.NamespaceName)).Value;
  3883. // var res2 = document.mainPart.GetRelationship(id2);
  3884. // string ans2 = res2.SourceUri.OriginalString;
  3885. // headers.odd.xml_filename = ans2;
  3886. // // Extract the first header reference
  3887. // var header_first_ref = sectPr.Elements().SingleOrDefault(x => x.Name.LocalName == "h
  3888. //eaderReference" && x.Attribute(XName.Get("type", DocX.w.NamespaceName)) != null && x.Attribute(XName.Get("type", DocX.w.NamespaceName)).Value == "first");
  3889. // string id3 = header_first_ref.Attribute(XName.Get("id", DocX.r.NamespaceName)).Value;
  3890. // var res3 = document.mainPart.GetRelationship(id3);
  3891. // string ans3 = res3.SourceUri.OriginalString;
  3892. // headers.first.xml_filename = ans3;
  3893. // // Extract the even footer reference
  3894. // var footer_even_ref = sectPr.Elements().SingleOrDefault(x => x.Name.LocalName == "footerReference" && x.Attribute(XName.Get("type", DocX.w.NamespaceName)) != null && x.Attribute(XName.Get("type", DocX.w.NamespaceName)).Value == "even");
  3895. // string id4 = footer_even_ref.Attribute(XName.Get("id", DocX.r.NamespaceName)).Value;
  3896. // var res4 = document.mainPart.GetRelationship(id4);
  3897. // string ans4 = res4.SourceUri.OriginalString;
  3898. // footers.even.xml_filename = ans4;
  3899. // // Extract the odd footer reference
  3900. // var footer_odd_ref = sectPr.Elements().SingleOrDefault(x => x.Name.LocalName == "footerReference" && x.Attribute(XName.Get("type", DocX.w.NamespaceName)) != null && x.Attribute(XName.Get("type", DocX.w.NamespaceName)).Value == "default");
  3901. // string id5 = footer_odd_ref.Attribute(XName.Get("id", DocX.r.NamespaceName)).Value;
  3902. // var res5 = document.mainPart.GetRelationship(id5);
  3903. // string ans5 = res5.SourceUri.OriginalString;
  3904. // footers.odd.xml_filename = ans5;
  3905. // // Extract the first footer reference
  3906. // var footer_first_ref = sectPr.Elements().SingleOrDefault(x => x.Name.LocalName == "footerReference" && x.Attribute(XName.Get("type", DocX.w.NamespaceName)) != null && x.Attribute(XName.Get("type", DocX.w.NamespaceName)).Value == "first");
  3907. // string id6 = footer_first_ref.Attribute(XName.Get("id", DocX.r.NamespaceName)).Value;
  3908. // var res6 = document.mainPart.GetRelationship(id6);
  3909. // string ans6 = res6.SourceUri.OriginalString;
  3910. // footers.first.xml_filename = ans6;
  3911. //}
  3912. document.Xml = document._mainDoc.Root.Element( w + "body" );
  3913. document._headers = headers;
  3914. document._footers = footers;
  3915. document._settingsPart = HelperFunctions.CreateOrGetSettingsPart( package );
  3916. var ps = package.GetParts();
  3917. //document.endnotesPart = HelperFunctions.GetPart();
  3918. foreach( var rel in document.PackagePart.GetRelationships() )
  3919. {
  3920. var uriString = "/word/" + rel.TargetUri.OriginalString.Replace( "/word/", "" ).Replace( "file://", "" );
  3921. switch( rel.RelationshipType )
  3922. {
  3923. case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/endnotes":
  3924. document._endnotesPart = package.GetPart( new Uri( uriString, UriKind.Relative ) );
  3925. using( TextReader tr = new StreamReader( document._endnotesPart.GetStream() ) )
  3926. document._endnotes = XDocument.Load( tr );
  3927. break;
  3928. case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/footnotes":
  3929. document._footnotesPart = package.GetPart( new Uri( uriString, UriKind.Relative ) );
  3930. using( TextReader tr = new StreamReader( document._footnotesPart.GetStream() ) )
  3931. document._footnotes = XDocument.Load( tr );
  3932. break;
  3933. case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles":
  3934. document._stylesPart = package.GetPart( new Uri( uriString, UriKind.Relative ) );
  3935. using( TextReader tr = new StreamReader( document._stylesPart.GetStream() ) )
  3936. document._styles = XDocument.Load( tr );
  3937. break;
  3938. case "http://schemas.microsoft.com/office/2007/relationships/stylesWithEffects":
  3939. document._stylesWithEffectsPart = package.GetPart( new Uri( uriString, UriKind.Relative ) );
  3940. using( TextReader tr = new StreamReader( document._stylesWithEffectsPart.GetStream() ) )
  3941. document._stylesWithEffects = XDocument.Load( tr );
  3942. break;
  3943. case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable":
  3944. document._fontTablePart = package.GetPart( new Uri( uriString, UriKind.Relative ) );
  3945. using( TextReader tr = new StreamReader( document._fontTablePart.GetStream() ) )
  3946. document._fontTable = XDocument.Load( tr );
  3947. break;
  3948. case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering":
  3949. document._numberingPart = package.GetPart( new Uri( uriString, UriKind.Relative ) );
  3950. using( TextReader tr = new StreamReader( document._numberingPart.GetStream() ) )
  3951. document._numbering = XDocument.Load( tr );
  3952. break;
  3953. default:
  3954. break;
  3955. }
  3956. }
  3957. }
  3958. private static void CopyStream( Stream input, Stream output, int bufferSize = 32768 )
  3959. {
  3960. byte[] buffer = new byte[ bufferSize ];
  3961. int read;
  3962. while( ( read = input.Read( buffer, 0, buffer.Length ) ) > 0 )
  3963. {
  3964. output.Write( buffer, 0, read );
  3965. }
  3966. }
  3967. private string GetNextFreeRelationshipID()
  3968. {
  3969. int id =
  3970. (
  3971. from r in this.PackagePart.GetRelationships()
  3972. where r.Id.Substring( 0, 3 ).Equals( "rId" )
  3973. select int.Parse( r.Id.Substring( 3 ) )
  3974. ).DefaultIfEmpty().Max();
  3975. // The convension for ids is rid01, rid02, etc
  3976. var newId = id.ToString();
  3977. int result;
  3978. if( int.TryParse( newId, out result ) )
  3979. return ( "rId" + ( result + 1 ) );
  3980. var guid = String.Empty;
  3981. do
  3982. {
  3983. guid = Guid.NewGuid().ToString();
  3984. } while( Char.IsDigit( guid[ 0 ] ) );
  3985. return guid;
  3986. }
  3987. private byte[] MergeArrays( byte[] array1, byte[] array2 )
  3988. {
  3989. byte[] result = new byte[ array1.Length + array2.Length ];
  3990. Buffer.BlockCopy( array2, 0, result, 0, array2.Length );
  3991. Buffer.BlockCopy( array1, 0, result, array2.Length, array1.Length );
  3992. return result;
  3993. }
  3994. private Hyperlink AddHyperlink( string text, Uri uri, string anchor )
  3995. {
  3996. var i = new XElement
  3997. (
  3998. XName.Get( "hyperlink", w.NamespaceName ),
  3999. new XAttribute( r + "id", string.Empty ),
  4000. new XAttribute( w + "history", "1" ),
  4001. !string.IsNullOrEmpty( anchor ) ? new XAttribute( w + "anchor", anchor ) : null,
  4002. new XElement( XName.Get( "r", w.NamespaceName ),
  4003. new XElement( XName.Get( "rPr", w.NamespaceName ),
  4004. new XElement( XName.Get( "rStyle", w.NamespaceName ),
  4005. new XAttribute( w + "val", "Hyperlink" ) ) ),
  4006. new XElement( XName.Get( "t", w.NamespaceName ), text ) )
  4007. );
  4008. var h = new Hyperlink( this, this.PackagePart, i );
  4009. h.text = text;
  4010. if( uri != null )
  4011. {
  4012. h.uri = uri;
  4013. }
  4014. this.AddHyperlinkStyleIfNotPresent();
  4015. return h;
  4016. }
  4017. #endregion
  4018. #region Constructors
  4019. internal DocX( DocX document, XElement xml )
  4020. : base( document, xml )
  4021. {
  4022. }
  4023. #endregion
  4024. #region IDisposable Members
  4025. /// <summary>
  4026. /// Releases all resources used by this document.
  4027. /// </summary>
  4028. /// <example>
  4029. /// If you take advantage of the using keyword, Dispose() is automatically called for you.
  4030. /// <code>
  4031. /// // Load document.
  4032. /// using (DocX document = DocX.Load(@"C:\Example\Test.docx"))
  4033. /// {
  4034. /// // The document is only in memory while in this scope.
  4035. ///
  4036. /// }// Dispose() is automatically called at this point.
  4037. /// </code>
  4038. /// </example>
  4039. /// <example>
  4040. /// This example is equilivant to the one above example.
  4041. /// <code>
  4042. /// // Load document.
  4043. /// DocX document = DocX.Load(@"C:\Example\Test.docx");
  4044. ///
  4045. /// // Do something with the document here.
  4046. ///
  4047. /// // Dispose of the document.
  4048. /// document.Dispose();
  4049. /// </code>
  4050. /// </example>
  4051. public void Dispose()
  4052. {
  4053. _package.Close();
  4054. }
  4055. #endregion
  4056. }
  4057. }