A C# Method to Import Block Definitions into AutoCAD - c#

I'm trying to write a method to programmatically import blocks into a drawing so that my .NET plugin can place instances of those blocks into the drawing. Right now my method looks like this:
/// <summary>
/// Method to programatically import all the blocks in a given list
/// </summary>
public static void ImportBlocks(string[] filesToTryToImport)
{
//Importing all the blocks
for (int i = 0; i < filesToTryToImport.Count(); i++)
{
if (filesToTryToImport[i].EndsWith(".dwg"))
{
try
{
Transaction tr = _database.TransactionManager.StartTransaction();
DocumentLock docLock = _activeDocument.LockDocument();
using (tr)
using (docLock)
{
BlockTable blkTbl = tr.GetObject(_database.BlockTableId, OpenMode.ForRead) as BlockTable;
// ToDo: Add files
}
}
catch (Autodesk.AutoCAD.Runtime.Exception ex)
{
_editor.WriteMessage("\nError during copy: " + ex.Message);
}
}
}
}
And what I want is for all the blocks whose filepaths are in the string array filesToTryToImport to appear as options when I go to insert a block
So, for example, if One-Inch-Block wasn't originally in the list but the file path to it was passed as a string in the array passed to this method it becomes an option.

Related

it isn't cohesive, and it doesn't abstract away any of the implementation details

My professor doesn't want all my code in one class. I am new to C# as well so I don't know how to make my code cohesive and have it abstract away any of the implementation details. Here is my code I have so far. I am trying to make multiple classes because this class has too many responsibilities and I don't know how to do that.
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
namespace SvgGenerator
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Please enter the name of the output file.");
string outputFile = Console.ReadLine() + ".svg";
Console.WriteLine("Do you want to manually enter the squares or read them from a file? Man or File?");
string fileRead = Console.ReadLine();
if (fileRead.Trim() == "Manually" || fileRead.Trim() == "manually" || fileRead.Trim() == "Man" || fileRead.Trim() == "man")
{
ManInput(outputFile);
}
if (fileRead.Trim() == "file" || fileRead.Trim() == "File")
{
FileInput(outputFile);
}
}
private static void FileInput(string outputFile)
{
Console.WriteLine("What is the name of the file?");
string titleFileName = Console.ReadLine();
StreamReader reader;
reader = new StreamReader(titleFileName);
string textFile = reader.ReadToEnd();
reader.Close();
string[] values = textFile.Split(',', '\n');
List<Square> squares = new List<Square>();
for (int i = 0; i < values.Length;)
{
int valueNumsX = int.Parse(values[i].Trim());
int valueNumsY = int.Parse(values[i + 1].Trim());
Square squareQ = new Square(Color.FromName(values[i + 2].Trim()), valueNumsX, valueNumsY);
squares.Add(squareQ);
if (i == values.Length - 3)
{
SvgBuilder svgBuilder = new SvgBuilder();
string SVG = svgBuilder.Build(squares);
FileCreator Myfilecreater = new FileCreator();
Myfilecreater.Create(outputFile, SVG);
}
i = i + 3;
}
}
private static void ManInput(string outputFile)
{
Console.WriteLine("How many squares do you want in your SVG file?");
string squareCount = Console.ReadLine();
int numSquareCount = Convert.ToInt32(squareCount);
Console.WriteLine("What are the colors of your squares?");
string[] squareColor = new string[numSquareCount];
List<Square> squares = new List<Square>();
for (int i = 0; i < numSquareCount; i++)
{
squareColor[i] = Console.ReadLine();
Square squareQ = new Square(Color.FromName(squareColor[i]), i*4, 0, 200);
squares.Add(squareQ);
if (i == numSquareCount - 1)
{
SvgBuilder svgBuilder = new SvgBuilder();
string SVG = svgBuilder.Build(squares);
FileCreator Myfilecreater = new FileCreator();
Myfilecreater.Create(outputFile, SVG);
}
}
}
}
}`
First of all you should separate classes or methods handling input from classes handling output. If is also typically a poor idea to mix UI from the functional parts, even if the the UI is a console for this case.
I would suggest using the following methods:
private static IEnumerable<Square> ReadSquaresFromFile(string filePath)
private static IEnumerable<Square> ReadSquaresFromConsole()
private static WriteToFile(IEnumerable<Square> squares, string filePath)
For such a simple program procedural programming should be just fine. You do not have to use object. But if you want to, you could for example create a interface like:
public interface ISquareSource(){
IEnumerable<Square> Get();
}
With a file-implementation, console-implementation etc.
Note that I have used string filePath as the file source/destination. If you ever write a library or API, please ensure you have an overlay that takes a stream. It is super annoying to have some data in memory and being forced to write it to a temporary file just because some developer only imagined reading from actual files.
You could also consider using switch statements for handling input, for example
switch(fileRead.Trim().ToLower()){
case "manually":
...
break;
case "file":
...
break;
default:
Console.WriteLine("Invalid input, expected 'manually' or 'file'
break;
Cohesion is the idea that code that does the same thing belongs together, and code that doesn't do the same thing doesn't belong together.
So, let's consider the FileInput function. At a glance, we can see that it does the following:
Prompts the user for a file name to load.
Opens the file.
Reads all of its content into memory.
Closes the file.
Parses the file content into an array of strings.
For each item in the array:
Parses some integral values.
Creates a Square object from those values.
If the index of the current item is equal to the length of the array less 3:
Instantiates a new SvgBuilder.
Invokes its Build method.
Instantiates a new FileCreator.
Invokes its Create method.
There's a lot going on here. Essentially, there are three separate kinds of work going on here that could be broken out into individual functions:
User input (arguably this could be part of the main function).
Call file deserialization function (reads the input file into memory and returns it as an array of strings).
Call main processing function (iterates over the array)
Performs calculations and creates of Square object.
If index of the current item is array length less 3:
Call Build SVG File function
Call File Creation function.
This is what your instructor is getting at.

C# and ANTLR4: Handling "include" directives when parsing a file

I’m in a situation that, using ANTLR, I’m trying to parse input files that contains references to other files inside them, just like #include "[insert file name]" of C language.
One suggested approach is:
Parse the root file, saving said references as nodes (so, specific Grammar rules)
Visit the tree searching for "reference" nodes
for each reference node, parse the file referenced and substitute the node with the newly generated tree
repeat this process recursively, to handle multiple levels of inclusions
The problem with this solution is that the referenced files might be completely partial (see includes inside the body of a C function). In order to parse such files, I would have to implement a different parser to handle the fragmented grammar.
Is there any valid/suggested approach to (literally) inject the new file inside the ongoing parsing process?
One solution to this problem can be achieved by overriding Scanner's behavior and specifically, the NextToken() method.
This is necassary since the EOF token cannot be handled by the ANTLR lexer grammar ( to my best knowledge ) and any actions
attached to the lexer rule recognizing the EOF are simply ignored (as shown in the code bellow). Thus, it is necessary to
implement this behaviour directly into the scanner method.
So assume we have a parser grammar
parser grammar INCParserGrammar;
#parser::members {
public static Stack<ICharStream> m_nestedfiles = new Stack<ICharStream>();
}
options { tokenVocab = INCLexerGrammar; }
/*
* Parser Rules
*/
compileUnit
: (include_directives | ANY )+ ENDOFFILE
;
include_directives : INCLUDEPREFIX FILE DQUOTE
;
A static public Stack<ICharStream> (i.e. mySpecialFileStack) should be introduced inside grammar's members. This stack will be used to store the Character Steams associated with the files that take part in the parsing. The Character Streams are push to
this stack as new files are encountered with the include statements
and a lexer grammar
lexer grammar INCLexerGrammar;
#lexer::header {
using System;
using System.IO;
}
#lexer::members {
string file;
ICharStream current;
}
/*
* Lexer Rules
*/
INCLUDEPREFIX : '#include'[ \t]+'"' {
Mode(INCLexerGrammar.FILEMODE);
};
// The following ruls has always less length matched string that the the rule above
ANY : ~[#]+ ;
ENDOFFILE : EOF { // Any actions in the this rule are ignored by the ANTLR lexer };
////////////////////////////////////////////////////////////////////////////////////////////////////////
mode FILEMODE;
FILE : [a-zA-Z][a-zA-Z0-9_]*'.'[a-zA-Z0-9_]+ { file= Text;
StreamReader s = new StreamReader(file);
INCParserGrammar.m_nestedfiles.Push(_input);
current =new AntlrInputStream(s);
};
DQUOTE: '"' {
this._input = current;
Mode(INCLexerGrammar.DefaultMode); };
The overriden body of NextToken() method will be placed in the .g4.cs file which purpose is to extend
the generated scanner class given that the generated scanner class is decorated with the "partial" keyword
After the partial Scanner Class associated to the given grammar is generated navigate to the source code of the
ANTLR4 Lexer Class as given in the ANTLR Runtime and Copy ALL the original code to this new method and,
in the middle do-while block (right after the try-catch block) add the following code:
if (this._input.La(1) == -1)
{
if ( mySpecialFileStack.Count == 0 )
this._hitEOF = true;
else
this._input = mySpecialFileStack.Pop();
}
The full body of the NextToken() method override is
public override IToken NextToken() {
int marker = this._input != null ? this._input.Mark() : throw new InvalidOperationException("nextToken requires a non-null input stream.");
label_3:
try {
while (!this._hitEOF) {
this._token = (IToken)null;
this._channel = 0;
this._tokenStartCharIndex = this._input.Index;
this._tokenStartCharPositionInLine = this.Interpreter.Column;
this._tokenStartLine = this.Interpreter.Line;
this._text = (string)null;
do {
this._type = 0;
int num;
try {
num = this.Interpreter.Match(this._input, this._mode);
} catch (LexerNoViableAltException ex) {
this.NotifyListeners(ex);
this.Recover(ex);
num = -3;
}
if (this._input.La(1) == -1) {
if (INCParserGrammar.m_nestedfiles.Count == 0 ) {
this._hitEOF = true;
}
else
{
this._input = INCParserGrammar.m_nestedfiles.Pop();
}
}
if (this._type == 0)
this._type = num;
if (this._type == -3)
goto label_3;
}
while (this._type == -2);
if (this._token == null)
this.Emit();
return this._token;
}
this.EmitEOF();
return this._token;
} finally {
this._input.Release(marker);
}
}
Now, when you recognize a file inside your code that should be parsed, simply add the following action
FILE
: [a-zA-Z][a-zA-Z0-9_]*'.'[a-zA-Z0-9_]+ {
StreamReader s = new StreamReader(Text);
mySpecialFileStack.Push(_input);
_input = new AntlrInputStream(s);
};
DQUOTE: '"' { this._input = current;
Mode(INCLexerGrammar.DefaultMode); };
//***Warning:***
// Be careful when your file inclusion is enclosed inside quotes or other symbols, or if
// the filename-to-be-included is not the last token that defines an inclusion: `_input`
// should only be switched AFTER the inclusion detection is completely found (i.e. after
// the closing quote has been recognized).
Finally the main program is given below where it is apparent that the root file is added first in the ICharStream stack
static void Main(string[] args) {
var a = new StreamReader("./root.txt");
var antlrInput = new AntlrInputStream(a);
INCParserGrammar.m_nestedfiles.Push(antlrInput);
var lexer = new INCLexerGrammar(antlrInput);
var tokens = new BufferedTokenStream(lexer);
var parser = new INCParserGrammar(tokens);
parser.compileUnit();
}
Reading Mr. Grigoris's answer helped me to discover another possible solution for my problem:
While trying to figure out how does the suggested solution work, I stumbled upon public virtual IToken EmitEOF() method. If the code that Mr. Grigoris provided gets placed inside this function (with minor changes), everything seems to work as intended.
That gave me the opportunity to override the functionality of EmitEOF() directly from #members block of lexer, without having to create a whole new file or to understand how my current parser's NextToken() method works.
Lexer Grammar:
lexer grammar INCLexerGrammar;
#lexer::header {
using System;
using System.IO;
using System.Collections.Generic;
}
#lexer::members {
private Stack<ICharStream> _nestedFiles = new Stack<ICharStream>();
public override IToken EmitEOF(){
if (_nestedFiles.Count == 0 ) {
return base.EmitEOF();
};
this._hitEOF = false;
this._input = _nestedFiles.Pop();
return this.NextToken();
}
}
/////////////////////////////////////////////////////////////////////////////////////
// Default Mode /////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
// Skipped because we don't want to hide INCLUDEPREFIX's existance from parser
INCLUDEPREFIX : '#include'[ \t]+'"' { Mode(INCLexerGrammar.FILEMODE); } -> skip;
// This is the only valid token our Grammar accepts
ANY : ~[#]+ ;
/////////////////////////////////////////////////////////////////////////////////////
mode FILEMODE; //////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
// Skipped because we don't want to hide FILE's existance from parser
FILE : [a-zA-Z][a-zA-Z0-9_]*'.'[a-zA-Z0-9_]+ {
// Create new StreamReader from the file mentioned
StreamReader s = new StreamReader(Text);
// Push the old stream to stack
_nestedFiles.Push(_input);
// This new stream will be popped and used right after, on DQUOTE.
_nestedFiles.Push(new AntlrInputStream(s));
} -> skip;
// Skipped because we don't want to hide DQUOTE's existance from parser
DQUOTE: '"' {
// Injecting the newly generated Stream.
this._input = _nestedFiles.Pop();
Mode(INCLexerGrammar.DefaultMode);
} -> skip;
Parser Grammar:
parser grammar INCParserGrammar;
options { tokenVocab = INCLexerGrammar; }
// Our Grammar contains only ANY tokens. Include directives
// and other Tokens exists only for helping lexer to
// inject the contents of other files inside the current
// scanning process.
compileUnit
: ANY+ EOF
;
Execution Calls:
// [...]
var myRootFile = new StreamReader("./root.txt");
var myAntlrInputStream = new AntlrInputStream(myRootFile);
var lexer = new INCLexerGrammar(myAntlrInputStream);
var tokens = new BufferedTokenStream(lexer);
var parser = new INCParserGrammar(tokens);
parser.compileUnit();
// [...]

How to avoid Reflected_xss_all_clients vulnerabilities in Winforms c#

Currently, I am working for a Winforms project.
When I am scanning my Winforms application through CheckMarx then I am getting multiple Reflected_xss_all_clients vulnerabilities.
I know there is no scripting in Winforms. XSS is a web threat but may be there would be some way to remediate these threats during scanning.
Here is the error code section 1:
private void UpdatePreviewValue()
{
try
{
// Set the preview value
if (txtFieldValue.Text != string.Empty)
{
// Show the preview value
lblPreview.Text = "(" + txtFieldValue.Text + ")";
}
else
{
// Show that there is no field value
lblPreview.Text = Properties.Resources.Std_Txt_Fld_NoFieldValue;
}
}
catch (Exception ex)
{
frmErrorHandler.ShowDataError(Properties.ErrorStrings.ErrorTitle_SrcFldCtlInteger_UpdatePreviewValue, DataErrorImageConstants.Exclamation, ex);
}
}
in above code section, the line lblPreview.Text = "(" + txtFieldValue.Text + ")";is throwing Reflected_xss_all_clients vulnerabilities.
Here is the error code section 2:
/// <summary>
/// Method to copy an existing node for moving inside a grid
/// </summary>
/// <param name="rowToCopy">GridRow to copy</param>
/// <returns>GridRow</returns>
private GridRow CopyGridRow(GridRow rowToCopy)
{
GridRow newRow = gridCategories.NewRow();
newRow.Tag = rowToCopy.Tag;
newRow.Cells[0].Text = rowToCopy.Cells[0].Text;
newRow.Cells[0].Image = rowToCopy.Cells[0].Image;
newRow.Cells[1].Text = rowToCopy.Cells[1].Text;
if (rowToCopy.HasRows)
{
foreach (GridRow nestedRow in rowToCopy.NestedRows)
{
newRow.NestedRows.Add(CopyGridRow(nestedRow));
}
}
return newRow;
}
in above code section, the line newRow.Cells[0].Text = rowToCopy.Cells[0].Text; and newRow.Cells[1].Text = rowToCopy.Cells[1].Text;are throwing Reflected_xss_all_clientsvulnerabilities.
Here is the error code section 3:
/// <summary>
/// Method used to add a new discrete value to the listview
/// </summary>
private void AddDiscreteValue()
{
// check we have an entry to add
if (txtDiscreteValue.Text != "")
{
SetDiscreteValue(txtDiscreteValue.Text, true, null, false);
}
}
In above code section, the line SetDiscreteValue(txtDiscreteValue.Text, true, null, false); is throwing Reflected_xss_all_clients vulnerabilities for txtDiscreteValue.Text
Please suggest any way to remediate it, if possible.
Checkmarx will follow the string from input to use. Sometimes it identifies a variable which is not fillterd transited to the frontend as a XSS.
As for me, I always ignore the XSS reported from Checkmarx. Maybe you can use a fillter function before use the string variable. Like this
txtFieldValue.Text=cleanXSS(txtFieldValue.Text)
As for cleanXSS(), you can find many examples after google.

System.Runtime.InteropServices.COMException: "Inappropriate source object for this action". is identified while retrieving the connected shapes

I am trying to get the connected shapes for every shape in my page. But I am finding a strange COM exception - "Inappropriate source object for this action"
Here's my code:
using Microsoft.Office.Interop.Visio;
class Program
{
static void Main(string[] args)
{
Application visApp = new Application();
Document visDoc = visApp.Documents.Open(filePath);
// Get the first page in the sample drawing.
page = visDoc.Pages[1];
foreach (Microsoft.Office.Interop.Visio.Shape shp in page.Shapes)
{
GetConnected(shp, Microsoft.Office.Interop.Visio.VisConnectedShapesFlags.visConnectedShapesOutgoingNodes, "", null, true);
}
}
private static void GetConnected(Microsoft.Office.Interop.Visio.Shape shp, Microsoft.Office.Interop.Visio.VisConnectedShapesFlags whichConnectedShapes, string category, Microsoft.Office.Interop.Visio.Selection selection, bool addToSelection)
{
Array aryTargetIDs;
//getting an exception here during the second iteration of for loop of Main method
aryTargetIDs = shp.ConnectedShapes(whichConnectedShapes, category);
}
}
The ConnectedShapes method throws this exception for 1D shapes (ie connectors). So you just need to include this check, either prior to calling your helper method or within it as per the following:
using Visio = Microsoft.Office.Interop.Visio
private static void GetConnected(
Visio.Shape shp,
Visio.VisConnectedShapesFlags whichConnectedShapes,
string category,
Visio.Selection selection,
bool addToSelection)
{
if (shp is null)
{
throw new ArgumentNullException();
}
if (shp.OneD == 0)
{
Array aryTargetIDs = shp.ConnectedShapes(whichConnectedShapes, category);
Console.WriteLine($"{shp.Master.Name} ({shp.NameID}) - {String.Join(", ", aryTargetIDs.Cast<object>().ToArray())}");
}
}
So given a set of shapes like this:
The console output from the above code would look something like this:
Start/End (Sheet.1) - 2
Decision (Sheet.2) - 4, 6
Subprocess (Sheet.4) -
Document (Sheet.6) -

Retrieving Building Blocks from user generated Word document

I've searched far and wide, and I haven't found a proper solution yet.
First off, this is a WinForms application using .NET 4.0 and DevExpress.
I've been attempting to retrieve Building Blocks (Watermarks, Cover Pages etc) from Word documents (.docx), or at least user generated template files (.dotx), that a user uploads to my application, which will then be saved to a database.
I must be able to retrieve all the Building Blocks used in that file.
I have tried a lot of different ways of retrieving them, but I can only retrieve them from the Built-In Building Blocks.dotx file, located in:
C:\Users\<username>\AppData\Roaming\Microsoft\Document Building Blocks\1033\14\Built-In Building Blocks.dotx
I haven't figured out how to extract them from a user generated file.
Here is work in progress code I've been using (many iterations so I can easily debug it):
private void SaveBuildingBlock(string savedFile)
{
try
{
Microsoft.Office.Interop.Word.ApplicationClass wordApplication = null;
wordApplication = new Microsoft.Office.Interop.Word.ApplicationClass();
Microsoft.Office.Interop.Word.Document wordDocument = wordApplication.Documents.OpenNoRepairDialog(savedFile);
object missing = System.Type.Missing;
Database.ToolbarItemsWordInsertFileData.FileData = FileHandler.FileByteLocked(savedFile);
Database.ToolbarItemsWordInsertFileData.Id = 0;
Database.ToolbarItemsWordInsertFileData.ToolbarItemId = ToolbarId;
Database.ToolbarItemsWordInsertFileData.Save();
ListBuildingBlocks(wordApplication, wordPage);
}
catch (Exception err)
{
Logger.Log(err);
}
}
Next method:
private void ListBuildingBlocks(Microsoft.Office.Interop.Word.Application wordApplication, WordPages wordPage)
{
Microsoft.Office.Interop.Word.WdBuildingBlockTypes type = wordPage == WordPages.CoverPage ? type = Microsoft.Office.Interop.Word.WdBuildingBlockTypes.wdTypeCoverPage : type = Microsoft.Office.Interop.Word.WdBuildingBlockTypes.wdTypeWatermarks;
for (int i = 1; i <= wordApplication.Templates.Count; i++)
{
try
{
if (wordApplication.Templates[i] != null)
{
Microsoft.Office.Interop.Word.Categories categories = wordApplication.Templates[i].BuildingBlockTypes.Item(type).Categories;
for (int c = 1; c <= categories.Count; c++)
{
try
{
//Category cat = categories.Application[0];
Microsoft.Office.Interop.Word.BuildingBlocks buildingBlocks = wordApplication.Templates[i].BuildingBlockTypes.Item(type).Categories.Item(categories.Item(c).Name).BuildingBlocks;
for (int b = 1; b <= buildingBlocks.Count; b++)
{
try
{
Microsoft.Office.Interop.Word.BuildingBlock buildingBlock = buildingBlocks.Item(b);
if (buildingBlock != null)
{
//saving to database occurs here
}
}
catch (Exception err)
{
MessageBox.Show(err.Message);
}
}
}
catch (Exception err)
{
MessageBox.Show(err.Message);
}
}
}
}
catch (Exception err)
{
MessageBox.Show(err.Message);
}
}
}
The WordPages parameter [wordPage] is used in the application to specify if it's a Watermark or Cover Page (it's a property in this user control).
You need to add it to the current list of add-ins, then you can open it as a template for working with building blocks. Apart from changing the attached template and loading it that way, I don't see any other way of doing this:
Dim app = Globals.ThisAddIn.Application
'load the file containing the building blocks
app.AddIns.Add("\\Path to File.dotx")
'get the object for the loaded template
Dim template = app.Templates(app.AddIns.Count)
'go through each building block in the file
For I = 1 to template.BuildingBlockEntries.Count
Dim bb = template.BuildingBlockEntries.Item(i)
Next
If you need to go down the xml route, the building blocks are stored inside the package in word\glossary\document.xml which is probably easier if you are doing this server side then you wont need to work with the word object model at all, just use the Open Xml SDK, it's pretty useful for things like this!

Categories

Resources