Implement full Prototype1b section parsing#1154
Conversation
This replaces the current ACIS data extraction with a reader for the entire Prototype1b section to reatin all handles, references and records. It also prevents potential extraction of corrupted / invalid data.
|
Hi @domeitzinger, I gave this branch a run against our test collection: 423 DWG files, a mix of real drawings from support cases and files written by ACadSharp itself. For every file I extracted the ACIS payloads per handle (count and content hash) with current master and with this branch, then compared the two reports.
To be clear, I think a full section model is the right direction to go, and these look like fixable robustness gaps rather than a problem with the approach itself. For the failing customer files I can share the parsed section details privately if that helps. Happy to rerun the comparison on iterations of this branch, the harness is ready. |
|
Thanks, here are some notes about your findings: The amount of ACIS files found can be different due to the section sometimes containing old file data that is not being referenced anymore and no longer being in use, but still stored in the file. Arguably this should not be the case very often as I have barely seen any files with this issue. And additionally I am not just parsing ACIS files with this, but actually all kinds of other files (e.g. thumbnail PNG, etc) as well. The counts you gave somehow indicate this only affects a handful of files where the "payloads" cannot be found. There might be something special about them that I have not encountered in any of my testing files. Changes in file size could be explainable by the issue I was pointing out that the implementation on the master branch might read data as an ACIS file that does not even belong to it at all (e.g. It would be helpful to know where the As for the 0 byte files: The reason is that the parser reads a file size of 0x62626262 which seems like a special pattern. This might have something to do with the And files which have been created with the AcDs writer from your open PR are expected not to work (or only work with specific files), as it generates an invalid Prototype1b segment and therefore it cannot be parsed. Otherwise I am not aware of the master branch being able to write the Prototype1b section and therefore it should not be able to find anything. Also, what exactly do you mean by "extracted the ACIS payloads per handle"? I cannot really do anything about those issues with no test files, as in all my test files it works flawlessly and I am not experiencing any issues. If it is possible for you to share those test files with me, I would be happy to take a look at this. |
|
Hi @domeitzinger, I took the time to dig into all three findings at the parser level. About your question on the method first, because it changes how to read my numbers. The harness reads each DWG with So I redid the comparison at section level, calling And it is not specific to files written by our PR. A customer file resaved by AutoCAD with 12 records in the data segment fails identically on your branch, first read The OverflowException file is a customer drawing I cannot share, but the parsed section layout is enough to see what happens, so I can just paste it. The current segment index sits at 0x680 (entry 46 of itself), but entry 0 points at 0x80, which holds an older, smaller segidx snapshot from a previous save, 0x80 bytes declared. So your old file data explanation is right. If a physical test case for the stale segidx would help, I can build a synthetic file with dummy geometry that reproduces the layout, just say the word. And once the anchor is in I will rerun the corpus, I expect the gap to close almost entirely. |
|
Well yeah, I did not try to do anything with the
|
|
Glad it converges. The spec correction matches what I hit empirically some time ago: that "data start marker (just after this list of data record headers)" wording in 24.2.2.3 is exactly what broke my reader on AutoCAD files with 9 or more records, where the payload area sits farther out. The only rule that held across every reference file I have is marker = segment start + ( The count 8 files with no padding fit the same picture: the filler is not mandatory and its size is whatever the anchor implies. The writer keeps the 16 byte gap because the AutoCAD fresh saves it mirrors do that at those counts, but a reader should never infer the marker from padding or alignment, only from the header field. On the dangling headers, agreed, they look like unreferenced leftovers. Master's extraction picks them up, which also inflates its counts in my comparison, so on the next corpus run I will compare referenced entries only. On the OverflowException, let me tie it to the dump I posted, since every number there comes from your parser reading that file. The current segidx is the one at 0x680, entry 46 of itself, matching And since testing material helps, I will try to build a synthetic file that reproduces that stale segidx layout with dummy geometry and attach it here. |
|
Rerun done on the updated branch (87a6ba6), same corpus of 423 files, this time comparing at section level and referenced entries only, as promised. Results:
The only remaining delta on the whole corpus is the OverflowException on the stale segidx file, unchanged as expected. About the synthetic file I promised for it: do you still need it? If you push a fix, the loop above works just as well, I run the real file against your branch and report back. But if a physical test case still helps, for a regression test for example, I will put it together. Nice work, the anchor fix closed the parsing gap completely. |
|
Thanks for trying. If I understand correctly, the issue is that the Segment index references a second Segment index section within the header. As far as I can tell from the ODA specs, only a single Segment index is valid per file (the one that is referenced in the file header). The only other way this would make any sense is, that some yet unknown field value might indicate how to handle such cases. But this is probably very specific to that file. It might also just be the case that AutoCAD simply ignores that entry as it is invalid. Any kind of synthetic or AI generated test files will not be very helpful in finding the issue. Generating a file that still causes the same issue will probably not indicate any solutions to the root problem. As this could probably be due to a combination of yet unknown values, you cannot know which fields are ok to change and which ones are not. It is also worth pointing out that it is important to know how those files were created, what software was used, etc. I am sorry, but it is a real pain to read through all your verbose AI generated responses. It almost feels like I am talking to a chatbot and I have to filter out all the actually useful information fom the huge wall of text. |
|
Fair point on the length, keeping it short. No synthetic file then, dropped. In the meantime I asked the customer who owns that drawing for permission to share it: if they agree, I will gladly send it over. And agreed on the segidx: one valid segment index per file, the extra entry is stale data, and skipping it (or bounding the entry loop by the declared segment size) matches what the reference consumers do, since they read that file fine. The rerun offer stands whenever you update the branch. |
| public FreeSpace FreeSpace { get; set; } | ||
| } | ||
|
|
||
| public class DataStorage |
There was a problem hiding this comment.
The data storage is misspaced in the project, if this is the class that contains the binary data in the file it should be in the base namespace or in a dedicated one along with the other classes, I don't think it belongs to the DwgStreamReaders.
There was a problem hiding this comment.
I would move the classes related to DataStorage to the namespace ACadSharp.Acis (or a better name 😁)
In separated files please.
There was a problem hiding this comment.
Yeah, I kept all in one file to make debugging a bit easier (same reason for the reader inside the DataStorage). I will put the reader from the DataStorage into the DwgPrototype1bReader and move the classes to their separate namespace. I would probably rather use something like ACadSharp.Prototype as the DataStorage is not specific to ACIS files and contains other formats as well e.g. Thumbnail PNG files, etc.
|
|
||
| private readonly IDwgStreamReader _reader; | ||
|
|
||
| internal DataStorage(IDwgStreamReader reader) |
There was a problem hiding this comment.
Is there an advantage to have the reading in the DataStorage class?
The current architecture of the project uses readers like DwgPrototype1bReader to process the information and create the objects, the object should be agnostic to the readers, writers or the format dwg/dxf.
| var reader = new DwgPrototype1bReader(this._fileHeader.AcadVersion, sreader); | ||
| reader.OnNotification += onNotificationEvent; | ||
|
|
||
| this._document.DataStorage = reader.Read(); |
There was a problem hiding this comment.
Please add a try, catch on the reading process to make it safe regarding the result.
There was a problem hiding this comment.
Well sure, I can do that, but I left it out as I am thinking of a possible future scenario where the Prototype1b header failed to be read and then the file is saved again. The exception would be caught and the user of the library might be unaware of the issue (the only way to notice would be to subscribe to the notification event of the reader and see an error message). Then saving the file again will cause the Prototype1b section to be missing.
|
First of, thank you both for the effort and implication with the project! I really appreciate all the work that you are doing. Now for the review of this PR, I've posted a few comments regarding the format and structure, format and architecture of the code, please feel free to discuss or propose any alternatives. For the reading capability I would not be able to do a proper review giving that it will take some time to jump on the documentation and review bit by bit the reading process, so seeing that you both have run real case tests and I'll do the same with my files, if nothing crashes I'll consider the functionality valid to go into master. To ensure that there are no major issues to the reading process please take in special account this comment: Again, thanks a lot for the amazing work! |
This PR implements the full Prototype1b section parsing for DWG files. This section is primarily used to store ACIS and thumbnail data (but also other binary data). It replaces the current ACIS data extraction logic added in #1139 and #1146.
There are still a few unknown values, but the reader should be able to reliably parse the full section. Also it still is relatively low level (e.g. when adding / removing schemas or entries you would have to manually add the appropriate search schema references, data index entries, etc.). This is primarily due to the lack of understanding on what the exact purpose of the search schema is and the relationships between the different records. Therefore it is fully working as a reader, but trying to modify the data would still require some more investigation.
I still left the current ACIS data extraction DXF implementation and only replaced it in the DWG reader logic. As discussed in #1152, that implementation could cause extraction of invalid / corrupted data under specific circumstances and would require a solution similar to this PR.
Tasks done in this PR
Related Issues / Pull Requests