public static string CheckHeaderVariable(Stream stream, string headerVariable, out bool isBinary) { ICodeValueReader chunk; isBinary = IsBinary(stream); if (isBinary) chunk = new BinaryCodeValueReader(new BinaryReader(stream), Encoding.ASCII); else chunk = new TextCodeValueReader(new StreamReader(stream)); chunk.Next(); while (chunk.ReadString() != DxfObjectCode.EndOfFile) { chunk.Next(); if (chunk.ReadString() == DxfObjectCode.HeaderSection) { chunk.Next(); while (chunk.ReadString() != DxfObjectCode.EndSection) { string varName = chunk.ReadString(); chunk.Next(); if (varName == headerVariable) { // we found the variable we are looking for stream.Position = 0; return chunk.ReadString(); } // some header variables have more than one entry while (chunk.Code != 0 && chunk.Code != 9) chunk.Next(); } // we only need to read the header section stream.Position = 0; return null; } } stream.Position = 0; return null; }
/// <summary> /// Reads the whole stream. /// </summary> /// <param name="stream">Stream.</param> public DxfDocument Read(Stream stream) { if (stream == null) throw new ArgumentNullException(nameof(stream)); string dwgcodepage = CheckHeaderVariable(stream, HeaderVariableCode.DwgCodePage, out this.isBinary); try { if (this.isBinary) { Encoding encoding; DxfVersion version = DxfDocument.CheckDxfFileVersion(stream, out this.isBinary); if (version >= DxfVersion.AutoCad2007) encoding = Encoding.UTF8; // the strings in a dxf binary file seems to be stored as UTF8 even if the file looks like ANSI else { if (string.IsNullOrEmpty(dwgcodepage)) encoding = Encoding.GetEncoding(Encoding.Default.WindowsCodePage); // use the default windows code page, if unable to read the code page header variable. else { int codepage; encoding = Encoding.GetEncoding(int.TryParse(dwgcodepage.Split('_')[1], out codepage) ? codepage : Encoding.Default.WindowsCodePage); } } this.chunk = new BinaryCodeValueReader(new BinaryReader(stream), encoding); } else { Encoding encoding; Encoding encodingType = EncodingType.GetType(stream); bool isUnicode = (encodingType.EncodingName == Encoding.UTF8.EncodingName) || (encodingType.EncodingName == Encoding.BigEndianUnicode.EncodingName) || (encodingType.EncodingName == Encoding.Unicode.EncodingName); if (isUnicode) encoding = Encoding.UTF8; else { // if the file is not UTF-8 use the code page provided by the dxf file if (string.IsNullOrEmpty(dwgcodepage)) encoding = Encoding.GetEncoding(Encoding.Default.WindowsCodePage); // use the default windows code page, if unable to read the code page header variable. else { int codepage; encoding = Encoding.GetEncoding(!int.TryParse(dwgcodepage.Split('_')[1], out codepage) ? Encoding.Default.WindowsCodePage : codepage); } } this.chunk = new TextCodeValueReader(new StreamReader(stream, encoding, true)); } } catch (Exception ex) { throw new IOException("Unknown error opening the reader.", ex); } this.doc = new DxfDocument(new HeaderVariables(), false); this.entityList = new Dictionary<EntityObject, string>(); this.viewports = new Dictionary<Viewport, string>(); this.hatchToPaths = new Dictionary<Hatch, List<HatchBoundaryPath>>(); this.hatchContourns = new Dictionary<HatchBoundaryPath, List<string>>(); this.decodedStrings = new Dictionary<string, string>(); this.leaderAnnotation = new Dictionary<Leader, string>(); // blocks this.nestedInserts = new Dictionary<Insert, string>(); this.nestedDimensions = new Dictionary<Dimension, string>(); this.blockRecords = new Dictionary<string, BlockRecord>(StringComparer.OrdinalIgnoreCase); this.blockEntities = new Dictionary<Block, List<EntityObject>>(); // objects this.dictionaries = new Dictionary<string, DictionaryObject>(StringComparer.OrdinalIgnoreCase); this.groupEntities = new Dictionary<Group, List<string>>(); this.dimStyleToHandles = new Dictionary<DimensionStyle, string[]>(); this.imageDefReactors = new Dictionary<string, ImageDefinitionReactor>(StringComparer.OrdinalIgnoreCase); this.imgDefHandles = new Dictionary<string, ImageDefinition>(StringComparer.OrdinalIgnoreCase); this.imgToImgDefHandles = new Dictionary<Image, string>(); this.mLineToStyleNames = new Dictionary<MLine, string>(); this.underlayToDefinitionHandles = new Dictionary<Underlay, string>(); this.underlayDefHandles = new Dictionary<string, UnderlayDefinition>(); // for layouts errors workarounds this.blockRecordPointerToLayout = new Dictionary<string, BlockRecord>(StringComparer.OrdinalIgnoreCase); this.orphanLayouts = new List<Layout>(); this.chunk.Next(); // read the comments at the head of the file, any other comments will be ignored // they sometimes hold information about the program that has generated the dxf // binary files do not contain any comments this.doc.Comments.Clear(); while (this.chunk.Code == 999) { this.doc.Comments.Add(this.chunk.ReadString()); this.chunk.Next(); } while (this.chunk.ReadString() != DxfObjectCode.EndOfFile) { if (this.chunk.ReadString() == DxfObjectCode.BeginSection) { this.chunk.Next(); switch (this.chunk.ReadString()) { case DxfObjectCode.HeaderSection: this.ReadHeader(); break; case DxfObjectCode.ClassesSection: this.ReadClasses(); break; case DxfObjectCode.TablesSection: this.ReadTables(); break; case DxfObjectCode.BlocksSection: this.ReadBlocks(); break; case DxfObjectCode.EntitiesSection: this.ReadEntities(); break; case DxfObjectCode.ObjectsSection: this.ReadObjects(); break; case DxfObjectCode.ThumbnailImageSection: this.ReadThumbnailImage(); break; case DxfObjectCode.AcdsDataSection: this.ReadAcdsData(); break; default: throw new Exception(string.Format("Unknown section {0}.", this.chunk.ReadString())); } } this.chunk.Next(); } stream.Position = 0; // perform all necessary post processes this.PostProcesses(); // to play safe we will add the default table objects to the document in case they do not exist, // if they already present nothing is overridden // add default layer this.doc.Layers.Add(Layer.Default); // add default line types this.doc.Linetypes.Add(Linetype.ByLayer); this.doc.Linetypes.Add(Linetype.ByBlock); this.doc.Linetypes.Add(Linetype.Continuous); // add default text style this.doc.TextStyles.Add(TextStyle.Default); // add default application registry this.doc.ApplicationRegistries.Add(ApplicationRegistry.Default); // add default dimension style this.doc.DimensionStyles.Add(DimensionStyle.Default); // add default MLine style this.doc.MlineStyles.Add(MLineStyle.Default); this.doc.ActiveLayout = Layout.ModelSpaceName; return this.doc; }
/// <summary> /// Reads the whole stream. /// </summary> /// <param name="stream">Stream.</param> public DxfDocument Read(Stream stream) { if (stream == null) throw new ArgumentNullException("stream", "The stream cannot be null"); string dwgcodepage = CheckHeaderVariable(stream, HeaderVariableCode.DwgCodePage, out this.isBinary); try { if (this.isBinary) { Encoding encoding; DxfVersion version = DxfDocument.CheckDxfFileVersion(stream, out this.isBinary); if (version >= DxfVersion.AutoCad2007) encoding = Encoding.UTF8; // the strings in a dxf binary file seems to be stored as UTF8 even if the file looks like ANSI else { if (string.IsNullOrEmpty(dwgcodepage)) encoding = Encoding.GetEncoding(Encoding.Default.WindowsCodePage); // use the default windows code page, if unable to read the code page header variable. else { int codepage; if (!int.TryParse(dwgcodepage.Split('_')[1], out codepage)) encoding = Encoding.GetEncoding(Encoding.Default.WindowsCodePage); // use the default windows code page, if unable to read the code page header variable. else encoding = Encoding.GetEncoding(codepage); } } this.chunk = new BinaryCodeValueReader(new BinaryReader(stream), encoding); } else { Encoding encoding; Encoding encodingType = EncodingType.GetType(stream); bool isUnicode = (encodingType.EncodingName == Encoding.UTF8.EncodingName) || (encodingType.EncodingName == Encoding.BigEndianUnicode.EncodingName) || (encodingType.EncodingName == Encoding.Unicode.EncodingName); if (isUnicode) encoding = Encoding.UTF8; else { // if the file is not UTF-8 use the code page provided by the dxf file if (string.IsNullOrEmpty(dwgcodepage)) encoding = Encoding.GetEncoding(Encoding.Default.WindowsCodePage); // use the default windows code page, if unable to read the code page header variable. else { int codepage; if (!int.TryParse(dwgcodepage.Split('_')[1], out codepage)) encoding = Encoding.GetEncoding(Encoding.Default.WindowsCodePage); // use the default windows code page, if unable to read the code page header variable. else encoding = Encoding.GetEncoding(codepage); // use the default windows code page, if unable to read the code page header variable. } } this.chunk = new TextCodeValueReader(new StreamReader(stream, encoding, true)); } } catch (Exception ex) { throw (new DxfException("Unknown error opening the reader.", ex)); } this.doc = new DxfDocument(new HeaderVariables(), false); this.entityList = new Dictionary<EntityObject, string>(); this.viewports = new Dictionary<Viewport, string>(); this.hatchToPaths = new Dictionary<Hatch, List<HatchBoundaryPath>>(); this.hatchContourns = new Dictionary<HatchBoundaryPath, List<string>>(); this.decodedStrings = new Dictionary<string, string>(); // blocks this.nestedInserts = new Dictionary<Insert, string>(); this.nestedDimensions = new Dictionary<Dimension, string>(); this.blockRecords = new Dictionary<string, BlockRecord>(StringComparer.OrdinalIgnoreCase); this.blockEntities = new Dictionary<Block, List<EntityObject>>(); // objects this.dictionaries = new Dictionary<string, DictionaryObject>(StringComparer.OrdinalIgnoreCase); this.groupEntities = new Dictionary<Group, List<string>>(); this.dimStyleToHandles = new Dictionary<DimensionStyle, string[]>(); this.imageDefReactors = new Dictionary<string, ImageDefReactor>(StringComparer.OrdinalIgnoreCase); this.imgDefHandles = new Dictionary<string, ImageDef>(StringComparer.OrdinalIgnoreCase); this.imgToImgDefHandles = new Dictionary<Image, string>(); this.mLineToStyleNames = new Dictionary<MLine, string>(); // for layouts errors workarounds this.blockRecordPointerToLayout = new Dictionary<string, BlockRecord>(StringComparer.OrdinalIgnoreCase); this.orphanLayouts = new List<Layout>(); this.chunk.Next(); // read the comments at the head of the file, any other comments will be ignored // they sometimes hold information about the program that has generated the dxf // binary files do not contain any comments this.doc.Comments.Clear(); while (this.chunk.Code == 999) { this.doc.Comments.Add(this.chunk.ReadString()); this.chunk.Next(); } while (this.chunk.ReadString() != DxfObjectCode.EndOfFile) { if (this.chunk.ReadString() == DxfObjectCode.BeginSection) { this.chunk.Next(); switch (this.chunk.ReadString()) { case DxfObjectCode.HeaderSection: this.ReadHeader(); break; case DxfObjectCode.ClassesSection: this.ReadClasses(); break; case DxfObjectCode.TablesSection: this.ReadTables(); break; case DxfObjectCode.BlocksSection: this.ReadBlocks(); break; case DxfObjectCode.EntitiesSection: this.ReadEntities(); break; case DxfObjectCode.ObjectsSection: this.ReadObjects(); break; case DxfObjectCode.ThumbnailImageSection: this.ReadThumbnailImage(); break; case DxfObjectCode.AcdsDataSection: this.ReadAcdsData(); break; default: throw new InvalidDxfSectionException(this.chunk.ReadString(), string.Format("Unknown section {0}.", this.chunk.ReadString())); } } this.chunk.Next(); } stream.Position = 0; // post process the dimension style list to assign the variables DIMTXSTY, DIMBLK, DIMBLK1, DIMBLK2, DIMLTYPE, DILTEX1, and DIMLTEX2 foreach (KeyValuePair<DimensionStyle, string[]> pair in this.dimStyleToHandles) { DimensionStyle defaultDim = DimensionStyle.Default; BlockRecord record; record = this.doc.GetObjectByHandle(pair.Value[0]) as BlockRecord; pair.Key.DIMBLK = record == null ? null : this.doc.Blocks[record.Name]; record = this.doc.GetObjectByHandle(pair.Value[1]) as BlockRecord; pair.Key.DIMBLK1 = record == null ? null : this.doc.Blocks[record.Name]; record = this.doc.GetObjectByHandle(pair.Value[2]) as BlockRecord; pair.Key.DIMBLK2 = record == null ? null : this.doc.Blocks[record.Name]; TextStyle txtStyle; txtStyle = this.doc.GetObjectByHandle(pair.Value[3]) as TextStyle; pair.Key.DIMTXSTY = txtStyle == null ? this.doc.TextStyles[defaultDim.DIMTXSTY.Name] : this.doc.TextStyles[txtStyle.Name]; LineType ltype; ltype = this.doc.GetObjectByHandle(pair.Value[4]) as LineType; pair.Key.DIMLTYPE = ltype == null ? this.doc.LineTypes[defaultDim.DIMLTYPE.Name] : this.doc.LineTypes[ltype.Name]; ltype = this.doc.GetObjectByHandle(pair.Value[5]) as LineType; pair.Key.DIMLTEX1 = ltype == null ? this.doc.LineTypes[defaultDim.DIMLTEX1.Name] : this.doc.LineTypes[ltype.Name]; ltype = this.doc.GetObjectByHandle(pair.Value[6]) as LineType; pair.Key.DIMLTEX2 = ltype == null ? this.doc.LineTypes[defaultDim.DIMLTEX2.Name] : this.doc.LineTypes[ltype.Name]; } // post process the image list to assign their image definitions. foreach (KeyValuePair<Image, string> pair in this.imgToImgDefHandles) { Image image = pair.Key; image.Definition = this.imgDefHandles[pair.Value]; image.Definition.Reactors.Add(image.Handle, this.imageDefReactors[image.Handle]); // we still need to set the definitive image size, now that we know all units involved double factor = UnitHelper.ConversionFactor(this.doc.DrawingVariables.InsUnits, this.doc.RasterVariables.Units); image.Width *= factor; image.Height *= factor; } // post process the MLines to assign their MLineStyle foreach (KeyValuePair<MLine, string> pair in this.mLineToStyleNames) { MLine mline = pair.Key; mline.Style = this.GetMLineStyle(pair.Value); } // post process the entities of the blocks foreach (KeyValuePair<Block, List<EntityObject>> pair in this.blockEntities) { Block block = pair.Key; foreach (EntityObject entity in pair.Value) { // now that we have all information required by the block entities we can add them to the document // entities like MLine and Image require information that is defined AFTER the block section, // this is the case of the MLineStyle and ImageDef that are described in the objects section block.Entities.Add(entity); } } // add the dxf entities to the document foreach (KeyValuePair<EntityObject, string> pair in this.entityList) { Layout layout; Block block; if (pair.Value == null) { // the Model layout is the default in case the entity has not one defined layout = this.doc.Layouts[Layout.ModelSpaceName]; block = layout.AssociatedBlock; } else { block = this.GetBlock(((BlockRecord) this.doc.GetObjectByHandle(pair.Value)).Name); layout = block.Record.Layout; } // the viewport with id 1 is stored directly in the layout since it has no graphical representation Viewport viewport = pair.Key as Viewport; if (viewport != null) { if (viewport.Id == 1) { // the base layout viewport has always id = 1 and we will not add it to the entities list of the document. // this viewport has no graphical representation, it is the view of the paper space layout itself and it does not show the model. layout.Viewport = viewport; layout.Viewport.Owner = block; } else { this.doc.ActiveLayout = layout.Name; this.doc.AddEntity(pair.Key, false, false); } } else { // apply the units scale to the insertion scale (this is for not nested blocks) Insert insert = pair.Key as Insert; if (insert != null) { double scale = UnitHelper.ConversionFactor(this.doc.DrawingVariables.InsUnits, insert.Block.Record.Units); insert.Scale *= scale; } this.doc.ActiveLayout = layout.Name; this.doc.AddEntity(pair.Key, false, false); } } // assign a handle to the default layout viewports foreach (Layout layout in this.doc.Layouts) { if (layout.Viewport == null) continue; if (string.IsNullOrEmpty(layout.Viewport.Handle)) this.doc.NumHandles = layout.Viewport.AsignHandle(this.doc.NumHandles); } // post process viewports clipping boundaries foreach (KeyValuePair<Viewport, string> pair in this.viewports) { EntityObject entity = this.doc.GetObjectByHandle(pair.Value) as EntityObject; if (entity != null ) pair.Key.ClippingBoundary = entity; } // post process the hatch boundary paths foreach (KeyValuePair<Hatch, List<HatchBoundaryPath>> pair in this.hatchToPaths) { Hatch hatch = pair.Key; foreach (HatchBoundaryPath path in pair.Value) { List<string> entities = this.hatchContourns[path]; foreach (string handle in entities) { EntityObject entity = this.doc.GetObjectByHandle(handle) as EntityObject; if (entity != null) path.AddContour(entity); } hatch.BoundaryPaths.Add(path); } } // post process group entities foreach (KeyValuePair<Group, List<string>> pair in this.groupEntities) { foreach (string handle in pair.Value) { EntityObject entity = this.doc.GetObjectByHandle(handle) as EntityObject; if (entity != null) pair.Key.Entities.Add(entity); } } // to play safe we will add the default table objects to the document in case they do not exist, // if they already present nothing is overridden // add default layer this.doc.Layers.Add(Layer.Default); // add default line types this.doc.LineTypes.Add(LineType.ByLayer); this.doc.LineTypes.Add(LineType.ByBlock); this.doc.LineTypes.Add(LineType.Continuous); // add default text style this.doc.TextStyles.Add(TextStyle.Default); // add default application registry this.doc.ApplicationRegistries.Add(ApplicationRegistry.Default); // add default dimension style this.doc.DimensionStyles.Add(DimensionStyle.Default); // add default MLine style this.doc.MlineStyles.Add(MLineStyle.Default); this.doc.ActiveLayout = Layout.ModelSpaceName; return this.doc; }