TheSwamp
Code Red => .NET => Topic started by: tjr on January 23, 2009, 04:42:58 PM
-
I am running into some very strange behavior in AutoCAD 2008 when I try writing text strings to an XRecord. When I write a ResultBuffer with a text length of 51367 characters to resultbuffer.Data all is well. When I try to write an ResultBuffer with a text length of 68480 characters to resultbuffer.Data it drops most of my string and only hold on to 2946 characters of the text string.
Is there a max length of a DxfCode.Text (1) Xrecord? I've been digging around for quite a while now and I'm at a loss here.
Here is the code I'm using. Please note that this portion of code was run through a "translator" to convert from some old Boo code I had to C# so I could use it on my project and I haven't had time to refactor it. Hence the ugliness.
public void WriteBOMToDwgDatabase()
{
Database database;
IDisposable dbDis = (database = HostApplicationServices.WorkingDatabase) as IDisposable;
try
{
Transaction transaction;
IDisposable trDis = (transaction = database.TransactionManager.StartTransaction()) as IDisposable;
try
{
try
{
DBDictionary dictionary = (DBDictionary) transaction.GetObject(database.NamedObjectsDictionaryId, OpenMode.ForWrite);
DBDictionary newValue = null;
try
{
newValue = (DBDictionary) transaction.GetObject(dictionary.GetAt("ks_bom"), OpenMode.ForRead);
}
catch (Exception)
{
newValue = new DBDictionary();
dictionary.SetAt("ks_bom", newValue);
database.TransactionManager.AddNewlyCreatedDBObject(newValue, true);
}
DBDictionary bomItem = null;
try
{
bomItem = (DBDictionary) transaction.GetObject(newValue.GetAt("bom_item"), OpenMode.ForWrite);
}
catch (Exception)
{
bomItem = new DBDictionary();
newValue.SetAt("bom_item", bomItem);
database.TransactionManager.AddNewlyCreatedDBObject(bomItem, true);
}
Xrecord xrecord = null;
try
{
xrecord = (Xrecord)transaction.GetObject(bomItem.GetAt("bomItem"), OpenMode.ForWrite);
TypedValue[] values = new TypedValue[] { new TypedValue(1, this.writestring) };
ResultBuffer resbuf = new ResultBuffer(values);
xrecord.Data = resbuf;
}
catch (Exception)
{
xrecord = new Xrecord();
TypedValue[] values = new TypedValue[] { new TypedValue(1, this.writestring) };
ResultBuffer resbuf = new ResultBuffer(values);
xrecord.Data = resbuf;
bomItem.SetAt("bomItem", xrecord);
database.TransactionManager.AddNewlyCreatedDBObject(xrecord, true);
}
transaction.Commit();
}
finally
{
transaction.Dispose();
}
}
finally
{
if (trDis != null)
{
trDis.Dispose();
trDis = null;
}
}
}
finally
{
if (dbDis != null)
{
dbDis.Dispose();
dbDis = null;
}
}
}
-
I have never tried this.
You might be better off writing a class/function to break down the string into chunks and reassemble. Also remember XDATA has memory limitations too.
-
I haven't experienced it, but it looks suspiciously like you're hitting some sort of limit at 65535 characters, which just happens to be the biggest int that an unsigned 16-bit int can hold...
-
I'm with Sinc on this (ack!) :D
But I have to ask - what sort of text are you storing that is that large!?!?
-
1. Convert the string into a byte array.
2. create a memorystream to consume the array
3. deflate the stream
4. break the stream into 127 byte chunks
5. put the chunks in a resultbuffer
6. do the reverse to get the string
:lol:
I.e
[C#]
// <copyright file="RbIo.cs" company="DWM Cabinet Drawings LLC">
// Copyright (c) 2009 All Rights Reserved </copyright>
// <author>Daniel Marcotte</author>
// <email>Danielm103@gmail.com</email>
// <date>2009-01-04</date>
// <summary>Contains Code</summary>
// some code is from http://blogs.msdn.com/bclteam/archive/2005/06/15/429542.aspx
namespace AcIo
{
using System;
using System.Text;
using System.IO;
using System.IO.Compression;
using Autodesk.AutoCAD.DatabaseServices;
/// <summary>
/// Contains static methods for converting
/// a file to a Resultbuffer and back
/// </summary>
internal class RbIo
{
/// <summary>
/// Converts a string to a ResultBuffer
/// </summary>
/// <param name="str">String: String to Compress</param>
/// <param name="compress">Bool: use compression</param>
/// <returns>a new ResultBuffer</returns>
internal static ResultBuffer StringToResultBuffer(string str, bool compress)
{
ResultBuffer buf = new ResultBuffer();
System.Text.ASCIIEncoding coder = new System.Text.ASCIIEncoding();
using (MemoryStream fs = new MemoryStream(coder.GetBytes(str)))
{
using (MemoryStream ms = new MemoryStream())
{
if (compress)
{
Compress(fs, ms);
StreamToResultBuffer(ms, buf);
}
else
{
StreamToResultBuffer(fs, buf);
}
}
}
return buf;
}
/// <summary>
/// Converts a file to a ResultBuffer
/// </summary>
/// <param name="path">String: Path to file</param>
/// <param name="compress">Bool: use compression</param>
/// <returns>a new ResultBuffer</returns>
internal static ResultBuffer FileToResultBuffer(string path, bool compress)
{
if (!File.Exists(path))
{
throw new ArgumentException("File Does not Exist");
}
ResultBuffer buf = new ResultBuffer();
using (FileStream fs = File.OpenRead(path))
{
using (MemoryStream ms = new MemoryStream())
{
if (compress)
{
Compress(fs, ms);
StreamToResultBuffer(ms, buf);
}
else
{
StreamToResultBuffer(fs, buf);
}
}
fs.Close();
}
return buf;
}
/// <summary>
/// Coverts a ResultBuffer to a string
/// </summary>
/// <param name="buf">ResultBuffer: buffer to convert</param>
/// <param name="decompress">Bool: decompress</param>
/// <returns>A new String</returns>
internal static string ResultBufferToString(ResultBuffer buf, bool decompress)
{
if (buf == null)
{
throw new ArgumentNullException("ResultBuffer buffer");
}
System.Text.ASCIIEncoding coder = new System.Text.ASCIIEncoding();
string str = string.Empty;
using (MemoryStream fs = new MemoryStream())
{
using (MemoryStream ms = new MemoryStream())
{
if (decompress)
{
ResultBufferToStream(buf, ms);
Decompress(ms, fs);
}
else
{
ResultBufferToStream(buf, fs);
}
}
str = coder.GetString(fs.GetBuffer());
}
return str;
}
/// <summary>
/// Coverts a ResultBuffer to a file
/// </summary>
/// <param name="buf">ResultBuffer: buffer to convert</param>
/// <param name="path">String: File path</param>
/// <param name="decompress">Bool: decompress</param>
internal static void ResultBufferToFile(ResultBuffer buf, string path, bool decompress)
{
if (buf == null)
{
throw new ArgumentNullException("ResultBuffer buffer");
}
using (FileStream fs = new FileStream(path, FileMode.Create))
{
using (MemoryStream ms = new MemoryStream())
{
if (decompress)
{
ResultBufferToStream(buf, ms);
Decompress(ms, fs);
}
else
{
ResultBufferToStream(buf, fs);
}
}
fs.Close();
}
}
/// <summary>
/// Converts a resulf buffer to a stream
/// </summary>
/// <param name="buf">ResultBuffer: buffer to convert</param>
/// <param name="destination">destination stream</param>
/// Close the stream when you are done
internal static void ResultBufferToStream(ResultBuffer buf, Stream destination)
{
if (buf == null)
{
throw new ArgumentNullException("ResultBuffer buffer");
}
BinaryWriter br = new BinaryWriter(destination);
br.BaseStream.Position = 0;
foreach (TypedValue t in buf)
{
br.Write((byte[])t.Value);
}
br.BaseStream.Position = 0;
}
/// <summary>
/// Converts a Stream to a ResultBuffer
/// </summary>
/// <param name="source">Stream: Stream to convert</param>
/// <param name="buf">ResultBuffer: destination buffer</param>
internal static void StreamToResultBuffer(Stream source, ResultBuffer buf)
{
BinaryReader br = new BinaryReader(source);
br.BaseStream.Position = 0;
while (source.Position < br.BaseStream.Length)
{
if ((br.BaseStream.Length - br.BaseStream.Position) > 127)
{
buf.Add(new TypedValue((short)DxfCode.BinaryChunk, br.ReadBytes(127)));
}
else
{
buf.Add(new TypedValue(
(short)DxfCode.BinaryChunk,
br.ReadBytes(Convert.ToInt32(br.BaseStream.Length - br.BaseStream.Position))));
}
}
br.BaseStream.Position = 0;
}
/// <summary>
/// Compress stream
/// </summary>
/// <param name="source">Stream: source</param>
/// <param name="destination">Stream: destination</param>
internal static void Compress(Stream source, Stream destination)
{
using (GZipStream output = new GZipStream(destination, CompressionMode.Compress, true))
{
Pump(source, output);
}
}
/// <summary>
/// Decompress Stream
/// </summary>
/// <param name="source">Stream: source</param>
/// <param name="destination">Stream: destination</param>
internal static void Decompress(Stream source, Stream destination)
{
using (GZipStream input = new GZipStream(source, CompressionMode.Decompress))
{
Pump(input, destination);
}
}
/// <summary>
/// Helper function for Compress and Decompress
/// </summary>
/// <param name="input">Stream: input</param>
/// <param name="output">Stream: output</param>
private static void Pump(Stream input, Stream output)
{
byte[] bytes = new byte[4096];
int n;
while ((n = input.Read(bytes, 0, bytes.Length)) != 0)
{
output.Write(bytes, 0, n);
}
}
}
}
[/C#]
-
Thanks for the tips, I'll see what I can do.
The XRecord is essentially an XML dump of a DataSet that I use for a Bill of Material. I write the information to both an XRecord and a SQL Server database on every save. The reason for storing in both places is if someone were to copy a drawing the Bill of Material would come with it. Maybe I need to look into just using SQL Server for storage only.
The Bill of Material that is causing me grief is an XML dump of a DataSet that contains 4 tables of about 120 records each, hence the high character count.
-
I take it from this, he doesn't know about the 255 character
limit on strings in result buffers.
No, I don't. I'm not familiar with ResultBuffer's at all. I'd accept any advice.
-
The XRecord is essentially an XML dump of a DataSet that I use for a Bill of Material. I write the information to both an XRecord and a SQL Server database on every save. The reason for storing in both places is if someone were to copy a drawing the Bill of Material would come with it. .....
I think its a good idea, With the StringToResultBuffer()/ResultBufferToString() functions I just posted, you can store/get any amount of data you want.
Its just not real fast when you get above 1MB of data. :-)
-
The XRecord is essentially an XML dump of a DataSet that I use for a Bill of Material. I write the information to both an XRecord and a SQL Server database on every save. The reason for storing in both places is if someone were to copy a drawing the Bill of Material would come with it. .....
I think it’s a good idea, With the StringToResultBuffer()/ResultBufferToString() functions I just posted, you can store/get any amount of data you want.
It’s just not real fast when you get above 1MB of data. :-)
Speed isn't a concern for me. So you're thinking that beating up the code above would allow me to write more than 65,000 characters to my XRecord?
-
Yep, I have tested the FileToResultBuffer() function 2,011,136 bytes.. in an XRecord :-o
its pretty much the same thing I did here
http://www.theswamp.org/index.php?topic=26687.0
-
Thanks Dan, you saved my hide.
I will peruse the code and hopefully come up with a solution.