Skip to content

Commit 5e7b035

Browse files
authored
Merge pull request #981 from DomCR/dwg-AC1015
Refactor DWG AC15 file header writing and section logic
2 parents ae77202 + 7f63b02 commit 5e7b035

File tree

11 files changed

+661
-667
lines changed

11 files changed

+661
-667
lines changed

src/ACadSharp.Tests/Internal/DwgFileHeaderExploration.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using ACadSharp.IO;
22
using ACadSharp.IO.DWG;
3+
using ACadSharp.IO.DWG.FileHeaders;
34
using System.IO;
45
using Xunit;
56
using Xunit.Abstractions;

src/ACadSharp/ACadSharp.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
<PropertyGroup>
1818
<GenerateDocumentationFile>true</GenerateDocumentationFile>
1919
<PackageReadmeFile>README.md</PackageReadmeFile>
20-
<Version>3.4.8</Version>
20+
<Version>3.4.9</Version>
2121
<PackageOutputPath>../nupkg</PackageOutputPath>
2222
<SignAssembly>True</SignAssembly>
2323
<AssemblyOriginatorKeyFile>../ACadSharp.snk</AssemblyOriginatorKeyFile>

src/ACadSharp/IO/DWG/DwgReader.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
using ACadSharp.Exceptions;
1212
using ACadSharp.IO.DWG;
1313
using ACadSharp.IO.DWG.DwgStreamReaders;
14+
using ACadSharp.IO.DWG.FileHeaders;
1415

1516
namespace ACadSharp.IO
1617
{
Lines changed: 107 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -1,151 +1,135 @@
1-
using CSUtilities.Converters;
1+
using ACadSharp.IO.DWG.FileHeaders;
2+
using CSUtilities.Converters;
23
using System.Collections.Generic;
34
using System.IO;
4-
using System.Linq;
55
using System.Text;
66

7-
namespace ACadSharp.IO.DWG
7+
namespace ACadSharp.IO.DWG.DwgStreamWriters;
8+
9+
internal class DwgFileHeaderWriterAC15 : DwgFileHeaderWriterBase<DwgFileHeaderAC15>
810
{
9-
/*
10-
HEADER
11-
FILE HEADER
12-
DWG HEADER VARIABLES
13-
CRC
14-
CLASS DEFINITIONS
15-
TEMPLATE (R13 only, optional)
16-
PADDING (R13C3 AND LATER, 200 bytes, minutes the template section above if present)
17-
IMAGE DATA (PRE-R13C3)
18-
OBJECT DATA
19-
All entities, table entries, dictionary entries, etc. go in this
20-
section.
21-
OBJECT MAP
22-
OBJECT FREE SPACE (optional)
23-
TEMPLATE (R14-R15, optional)
24-
SECOND HEADER
25-
IMAGE DATA (R13C3 AND LATER)
26-
*/
27-
internal class DwgFileHeaderWriterAC15 : DwgFileHeaderWriterBase
11+
public override int FileHeaderSize { get { return 0x61; } }
12+
13+
public override int HandleSectionOffset
2814
{
29-
public override int HandleSectionOffset
15+
get
3016
{
31-
get
32-
{
33-
long offset = _fileHeaderSize;
34-
35-
foreach (var item in this._records)
36-
{
37-
if (item.Key == DwgSectionDefinition.AcDbObjects)
38-
break;
39-
40-
offset += item.Value.Item2.Length;
41-
}
42-
43-
return (int)offset;
44-
}
17+
return (int)(FileHeaderSize
18+
+ this._records[DwgSectionDefinition.AuxHeader].Stream.Length
19+
+ this._records[DwgSectionDefinition.Preview].Stream.Length
20+
+ this._records[DwgSectionDefinition.Header].Stream.Length
21+
+ this._records[DwgSectionDefinition.Classes].Stream.Length);
4522
}
23+
}
24+
25+
private const int _nRecords = 6;
4626

47-
protected override int _fileHeaderSize { get { return 0x61; } }
27+
private byte[] _endSentinel = new byte[16]
28+
{
29+
0x95,0xA0,0x4E,0x28,0x99,0x82,0x1A,0xE5,0x5E,0x41,0xE0,0x5F,0x9D,0x3A,0x4D,0x00
30+
};
4831

49-
private readonly Dictionary<string, (DwgSectionLocatorRecord, MemoryStream)> _records;
32+
private Dictionary<string, DwgSectionLocatorRecord> _records = new();
5033

51-
private byte[] _endSentinel = new byte[16]
34+
public DwgFileHeaderWriterAC15(
35+
System.IO.Stream stream,
36+
Encoding encoding,
37+
CadDocument document)
38+
: base(stream, encoding, document)
39+
{
40+
this._records = new Dictionary<string, DwgSectionLocatorRecord>
5241
{
53-
0x95,0xA0,0x4E,0x28,0x99,0x82,0x1A,0xE5,0x5E,0x41,0xE0,0x5F,0x9D,0x3A,0x4D,0x00
42+
{ DwgSectionDefinition.AuxHeader , new DwgSectionLocatorRecord(5) },
43+
{ DwgSectionDefinition.Preview , new DwgSectionLocatorRecord(null) },
44+
{ DwgSectionDefinition.Header , new DwgSectionLocatorRecord(0) },
45+
{ DwgSectionDefinition.Classes , new DwgSectionLocatorRecord(1) },
46+
{ DwgSectionDefinition.AcDbObjects , new DwgSectionLocatorRecord(null) },
47+
{ DwgSectionDefinition.Handles , new DwgSectionLocatorRecord(2) },
48+
{ DwgSectionDefinition.ObjFreeSpace, new DwgSectionLocatorRecord(3) },
49+
{ DwgSectionDefinition.Template , new DwgSectionLocatorRecord(4) },
5450
};
51+
}
5552

56-
public DwgFileHeaderWriterAC15(Stream stream, Encoding encoding, CadDocument model) : base(stream, encoding, model)
57-
{
58-
_records = new Dictionary<string, (DwgSectionLocatorRecord, MemoryStream)>
59-
{
60-
{ DwgSectionDefinition.Header , (new DwgSectionLocatorRecord(0), null) },
61-
{ DwgSectionDefinition.Classes , (new DwgSectionLocatorRecord(1), null) },
62-
{ DwgSectionDefinition.ObjFreeSpace, (new DwgSectionLocatorRecord(3), null) },
63-
{ DwgSectionDefinition.Template , (new DwgSectionLocatorRecord(4), null) },
64-
{ DwgSectionDefinition.AuxHeader , (new DwgSectionLocatorRecord(5), null) },
65-
{ DwgSectionDefinition.AcDbObjects , (new DwgSectionLocatorRecord(null), null) },
66-
{ DwgSectionDefinition.Handles , (new DwgSectionLocatorRecord(2), null) },
67-
{ DwgSectionDefinition.Preview , (new DwgSectionLocatorRecord(null), null) },
68-
};
69-
}
53+
public override void AddSection(string name, MemoryStream stream, bool isCompressed, int decompsize = 29696)
54+
{
55+
this._records[name].Stream = stream;
56+
}
7057

71-
public override void AddSection(string name, MemoryStream stream, bool isCompressed, int decompsize = 0x7400)
72-
{
73-
this._records[name].Item1.Size = stream.Length;
74-
this._records[name] = (this._records[name].Item1, stream);
75-
}
58+
public override void WriteFile()
59+
{
60+
this.setSeekers();
7661

77-
public override void WriteFile()
78-
{
79-
setRecordSeekers();
62+
this.writeFileHeader();
8063

81-
writeFileHeader();
64+
this.writeRecordStreams();
8265

83-
writeRecordStreams();
84-
}
66+
this._stream.Flush();
67+
}
8568

86-
private void setRecordSeekers()
69+
private void setSeekers()
70+
{
71+
var currOffset = this.FileHeaderSize;
72+
foreach (var kv in this._records)
8773
{
88-
long currOffset = _fileHeaderSize;
89-
foreach (var item in this._records.Values)
90-
{
91-
item.Item1.Seeker = currOffset;
92-
currOffset += item.Item2.Length;
93-
}
74+
var record = kv.Value;
75+
record.Seeker = currOffset;
76+
currOffset += (int)record.Stream.Length;
9477
}
78+
}
9579

96-
private void writeFileHeader()
97-
{
98-
MemoryStream memoryStream = new MemoryStream();
99-
100-
//0x00 6 “ACXXXX” version string
101-
IDwgStreamWriter writer = DwgStreamWriterBase.GetStreamWriter(this._version, memoryStream, this._encoding);
102-
writer.WriteBytes(Encoding.ASCII.GetBytes(this._document.Header.VersionString));
103-
//The next 7 starting at offset 0x06 are to be six bytes of 0
104-
//(in R14, 5 0’s and the ACADMAINTVER variable) and a byte of 1.
105-
writer.WriteBytes(new byte[7] { 0, 0, 0, 0, 0, 15, 1 });
106-
//At 0x0D is a seeker (4 byte long absolute address) for the beginning sentinel of the image data.
107-
writer.WriteRawLong(this._records[DwgSectionDefinition.Preview].Item1.Seeker);
108-
109-
writer.WriteByte(0x1B);
110-
writer.WriteByte(0x19);
111-
112-
//Bytes at 0x13 and 0x14 are a raw short indicating the value of the code page for this drawing file.
113-
114-
writer.WriteBytes(LittleEndianConverter.Instance.GetBytes(this.getFileCodePage()));
115-
writer.WriteBytes(LittleEndianConverter.Instance.GetBytes(6));
116-
117-
foreach (var item in this._records.Values.Select(r => r.Item1))
118-
{
119-
if (!item.Number.HasValue)
120-
continue;
121-
122-
this.writeRecord(writer, item);
123-
}
124-
125-
//CRC
126-
writer.WriteSpearShift();
127-
writer.WriteRawShort((short)CRC8StreamHandler.GetCRCValue(0xC0C1, memoryStream.GetBuffer(), 0L, memoryStream.Length));
128-
129-
//0x95,0xA0,0x4E,0x28,0x99,0x82,0x1A,0xE5,0x5E,0x41,0xE0,0x5F,0x9D,0x3A,0x4D,0x00
130-
writer.WriteBytes(_endSentinel);
80+
private void writeFileHeader()
81+
{
82+
System.IO.MemoryStream ms = new System.IO.MemoryStream();
83+
84+
//0x00 6 “ACXXXX” version string
85+
IDwgStreamWriter writer = DwgStreamWriterBase.GetStreamWriter(this._version, ms, this._encoding);
86+
writer.WriteBytes(Encoding.ASCII.GetBytes(this._document.Header.VersionString), 0, 6);
87+
//The next 7 starting at offset 0x06 are to be six bytes of 0
88+
//(in R14, 5 0’s and the ACADMAINTVER variable) and a byte of 1.
89+
writer.WriteBytes(new byte[7] { 0, 0, 0, 0, 0, 15, 1 });
90+
//At 0x0D is a seeker (4 byte long absolute address) for the beginning sentinel of the image data.
91+
writer.WriteRawLong(this._records[DwgSectionDefinition.Preview].Seeker);
92+
93+
writer.WriteByte(0x1B);
94+
writer.WriteByte(0x19);
95+
96+
//Bytes at 0x13 and 0x14 are a raw short indicating the value of the code page for this drawing file.
97+
writer.WriteBytes(LittleEndianConverter.Instance.GetBytes(this.getFileCodePage()));
98+
writer.WriteBytes(LittleEndianConverter.Instance.GetBytes(_nRecords), 0, 4);
99+
100+
this.writeRecord(writer, this._records[DwgSectionDefinition.Header]);
101+
this.writeRecord(writer, this._records[DwgSectionDefinition.Classes]);
102+
this.writeRecord(writer, this._records[DwgSectionDefinition.Handles]);
103+
this.writeRecord(writer, this._records[DwgSectionDefinition.ObjFreeSpace]);
104+
this.writeRecord(writer, this._records[DwgSectionDefinition.Template]);
105+
this.writeRecord(writer, this._records[DwgSectionDefinition.AuxHeader]);
106+
107+
//CRC
108+
writer.WriteSpearShift();
109+
writer.WriteRawShort((short)CRC8StreamHandler.GetCRCValue(0xC0C1, ms.GetBuffer(), 0L, ms.Length));
110+
111+
//0x95,0xA0,0x4E,0x28,0x99,0x82,0x1A,0xE5,0x5E,0x41,0xE0,0x5F,0x9D,0x3A,0x4D,0x00
112+
writer.WriteBytes(_endSentinel, 0, _endSentinel.Length);
113+
114+
this._stream.Write(ms.GetBuffer(), 0, (int)ms.Length);
115+
}
131116

132-
this._stream.Write(memoryStream.GetBuffer(), 0, (int)memoryStream.Length);
133-
}
117+
private void writeRecord(IDwgStreamWriter writer, DwgSectionLocatorRecord record)
118+
{
119+
//Record number (raw byte) | Seeker (raw long) | Size (raw long)
120+
writer.WriteByte((byte)record.Number.Value);
121+
writer.WriteRawLong(record.Seeker);
122+
writer.WriteRawLong(record.Stream.Length);
123+
}
134124

135-
private void writeRecord(IDwgStreamWriter writer, DwgSectionLocatorRecord record)
125+
private void writeRecordStreams()
126+
{
127+
foreach (DwgSectionLocatorRecord item in this._records.Values)
136128
{
137-
//Record number (raw byte) | Seeker (raw long) | Size (raw long)
138-
writer.WriteByte((byte)record.Number.Value);
139-
writer.WriteRawLong(record.Seeker);
140-
writer.WriteRawLong(record.Size);
141-
}
129+
if (item.Stream == null)
130+
continue;
142131

143-
private void writeRecordStreams()
144-
{
145-
foreach (var item in this._records.Values.Select(r => r.Item2))
146-
{
147-
this._stream.Write(item.GetBuffer(), 0, (int)item.Length);
148-
}
132+
this._stream.Write(item.Stream.GetBuffer(), 0, (int)item.Stream.Length);
149133
}
150134
}
151-
}
135+
}

0 commit comments

Comments
 (0)