/// <summary> /// Parses the given StreamReader to retrieve a LVL struct /// </summary> /// <param name="bytes"></param> public ListLevel(VirtualStreamReader reader, int length) : base(reader, length) { long startPos = this._reader.BaseStream.Position; //parse the fix part this.iStartAt = this._reader.ReadInt32(); this.nfc = this._reader.ReadByte(); int flag = this._reader.ReadByte(); this.jc = (byte)(flag & 0x03); this.fLegal = Utils.BitmaskToBool(flag, 0x04); this.fNoRestart = Utils.BitmaskToBool(flag, 0x08); this.fPrev = Utils.BitmaskToBool(flag, 0x10); this.fPrevSpace = Utils.BitmaskToBool(flag, 0x20); this.fWord6 = Utils.BitmaskToBool(flag, 0x40); this.rgbxchNums = new byte[9]; for (int i = 0; i < 9; i++) { this.rgbxchNums[i] = this._reader.ReadByte(); } this.ixchFollow = (FollowingChar)this._reader.ReadByte(); this.dxaSpace = this._reader.ReadInt32(); this.dxaIndent = this._reader.ReadInt32(); this.cbGrpprlChpx = this._reader.ReadByte(); this.cbGrpprlPapx = this._reader.ReadByte(); this.ilvlRestartLim = this._reader.ReadByte(); this.grfhic = this._reader.ReadByte(); //parse the variable part //read the group of papx sprms //this papx has no istd, so use PX to parse it var px = new PropertyExceptions(this._reader.ReadBytes(this.cbGrpprlPapx)); this.grpprlPapx = new ParagraphPropertyExceptions { grpprl = px.grpprl }; //read the group of chpx sprms this.grpprlChpx = new CharacterPropertyExceptions(this._reader.ReadBytes(this.cbGrpprlChpx)); //read the number text short strLen = this._reader.ReadInt16(); this.xst = Encoding.Unicode.GetString(this._reader.ReadBytes(strLen * 2)); long endPos = this._reader.BaseStream.Position; this._reader.BaseStream.Seek(startPos, System.IO.SeekOrigin.Begin); this._rawBytes = this._reader.ReadBytes((int)(endPos - startPos)); }
/// <summary> /// Extracts the TAPX SPRMs out of a PAPX /// </summary> /// <param name="papx"></param> public TablePropertyExceptions(ParagraphPropertyExceptions papx, VirtualStream dataStream) { this.grpprl = new List <SinglePropertyModifier>(); foreach (var sprm in papx.grpprl) { if (sprm.Type == SinglePropertyModifier.SprmType.TAP) { this.grpprl.Add(sprm); } else if ((int)sprm.OpCode == 0x646b) { IStreamReader reader = new VirtualStreamReader(dataStream); //there is a native TAP in the data stream uint fc = System.BitConverter.ToUInt32(sprm.Arguments, 0); //get the size of the following grpprl //byte[] sizebytes = new byte[2]; //dataStream.Read(sizebytes, 2, (int)fc); var sizebytes = reader.ReadBytes(fc, 2); ushort grpprlSize = System.BitConverter.ToUInt16(sizebytes, 0); //read the grpprl //byte[] grpprlBytes = new byte[grpprlSize]; //dataStream.Read(grpprlBytes); var grpprlBytes = reader.ReadBytes(grpprlSize); //parse the grpprl var externalPx = new PropertyExceptions(grpprlBytes); foreach (var sprmExternal in externalPx.grpprl) { if (sprmExternal.Type == SinglePropertyModifier.SprmType.TAP) { this.grpprl.Add(sprmExternal); } } } } }
/// <summary> /// Builds a CHP based on a CHPX /// </summary> /// <param name="styles">The stylesheet</param> /// <param name="chpx">The CHPX</param> public CharacterProperties(CharacterPropertyExceptions chpx, ParagraphPropertyExceptions parentPapx, WordDocument parentDocument) { setDefaultValues(); //get all CHPX in the hierarchy var chpxHierarchy = new List <CharacterPropertyExceptions>(); chpxHierarchy.Add(chpx); //add parent character styles buildHierarchy(chpxHierarchy, parentDocument.Styles, (ushort)getIsdt(chpx)); //add parent paragraph styles buildHierarchy(chpxHierarchy, parentDocument.Styles, parentPapx.istd); chpxHierarchy.Reverse(); //apply the CHPX hierarchy to this CHP foreach (var c in chpxHierarchy) { applyChpx(c, parentDocument); } }
/// <summary> /// Parses the bytes to retrieve a StyleSheetDescription /// </summary> /// <param name="bytes">The bytes</param> /// <param name="cbStdBase"></param> /// <param name="dataStream">The "Data" stream (optional, can be null)</param> public StyleSheetDescription(byte[] bytes, int cbStdBase, VirtualStream dataStream) { var bits = new BitArray(bytes); //parsing the base (fix part) if (cbStdBase >= 2) { //sti var stiBits = Utils.BitArrayCopy(bits, 0, 12); this.sti = (StyleIdentifier)Utils.BitArrayToUInt32(stiBits); //flags this.fScratch = bits[12]; this.fInvalHeight = bits[13]; this.fHasUpe = bits[14]; this.fMassCopy = bits[15]; } if (cbStdBase >= 4) { //stk var stkBits = Utils.BitArrayCopy(bits, 16, 4); this.stk = (StyleKind)Utils.BitArrayToUInt32(stkBits); //istdBase var istdBits = Utils.BitArrayCopy(bits, 20, 12); this.istdBase = (uint)Utils.BitArrayToUInt32(istdBits); } if (cbStdBase >= 6) { //cupx var cupxBits = Utils.BitArrayCopy(bits, 32, 4); this.cupx = (ushort)Utils.BitArrayToUInt32(cupxBits); //istdNext var istdNextBits = Utils.BitArrayCopy(bits, 36, 12); this.istdNext = (uint)Utils.BitArrayToUInt32(istdNextBits); } if (cbStdBase >= 8) { //bchUpe var bchBits = Utils.BitArrayCopy(bits, 48, 16); this.bchUpe = (ushort)Utils.BitArrayToUInt32(bchBits); } if (cbStdBase >= 10) { //flags this.fAutoRedef = bits[64]; this.fHidden = bits[65]; this.f97LidsSet = bits[66]; this.fCopyLang = bits[67]; this.fPersonalCompose = bits[68]; this.fPersonalReply = bits[69]; this.fPersonal = bits[70]; this.fNoHtmlExport = bits[71]; this.fSemiHidden = bits[72]; this.fLocked = bits[73]; this.fInternalUse = bits[74]; } if (cbStdBase >= 12) { //istdLink var istdLinkBits = Utils.BitArrayCopy(bits, 80, 12); this.istdLink = (uint)Utils.BitArrayToUInt32(istdLinkBits); //fHasOriginalStyle this.fHasOriginalStyle = bits[92]; } if (cbStdBase >= 16) { //rsid var rsidBits = Utils.BitArrayCopy(bits, 96, 32); this.rsid = Utils.BitArrayToUInt32(rsidBits); } //parsing the variable part //xstz byte characterCount = bytes[cbStdBase]; //characters are zero-terminated, so 1 char has 2 bytes: var name = new byte[characterCount * 2]; Array.Copy(bytes, cbStdBase + 2, name, 0, name.Length); //remove zero-termination this.xstzName = Encoding.Unicode.GetString(name); //parse the UPX structs int upxOffset = cbStdBase + 1 + (characterCount * 2) + 2; for (int i = 0; i < this.cupx; i++) { //find the next even byte border if (upxOffset % 2 != 0) { upxOffset++; } //get the count of bytes for UPX ushort cbUPX = System.BitConverter.ToUInt16(bytes, upxOffset); if (cbUPX > 0) { //copy the bytes var upxBytes = new byte[cbUPX]; Array.Copy(bytes, upxOffset + 2, upxBytes, 0, upxBytes.Length); if (this.stk == StyleKind.table) { //first upx is TAPX; second PAPX, third CHPX switch (i) { case 0: this.tapx = new TablePropertyExceptions(upxBytes); break; case 1: this.papx = new ParagraphPropertyExceptions(upxBytes, dataStream); break; case 2: this.chpx = new CharacterPropertyExceptions(upxBytes); break; } } else if (this.stk == StyleKind.paragraph) { //first upx is PAPX, second CHPX switch (i) { case 0: this.papx = new ParagraphPropertyExceptions(upxBytes, dataStream); break; case 1: this.chpx = new CharacterPropertyExceptions(upxBytes); break; } } else if (this.stk == StyleKind.list) { //list styles have only one PAPX switch (i) { case 0: this.papx = new ParagraphPropertyExceptions(upxBytes, dataStream); break; } } else if (this.stk == StyleKind.character) { //character styles have only one CHPX switch (i) { case 0: this.chpx = new CharacterPropertyExceptions(upxBytes); break; } } } //increase the offset for the next run upxOffset += (2 + cbUPX); } }