Author Topic: Xrecord.Data Max Length  (Read 9532 times)

0 Members and 1 Guest are viewing this topic.

tjr

  • Guest
Xrecord.Data Max Length
« 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.
Code: [Select]
       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;
                }
            }
        }

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8659
  • AKA Daniel
Re: Xrecord.Data Max Length
« Reply #1 on: January 23, 2009, 04:57:13 PM »
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.

sinc

  • Guest
Re: Xrecord.Data Max Length
« Reply #2 on: January 23, 2009, 05:00:38 PM »
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...

Glenn R

  • Guest
Re: Xrecord.Data Max Length
« Reply #3 on: January 23, 2009, 05:33:59 PM »
I'm with Sinc on this (ack!) :D

But I have to ask - what sort of text are you storing that is that large!?!?

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8659
  • AKA Daniel
Re: Xrecord.Data Max Length
« Reply #4 on: January 23, 2009, 08:38:49 PM »
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

Code: [Select]
[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#]

tjr

  • Guest
Re: Xrecord.Data Max Length
« Reply #5 on: January 23, 2009, 11:45:20 PM »
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.

tjr

  • Guest
Re: Xrecord.Data Max Length
« Reply #6 on: January 23, 2009, 11:47:26 PM »
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.

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8659
  • AKA Daniel
Re: Xrecord.Data Max Length
« Reply #7 on: January 24, 2009, 12:19:38 AM »
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.  :-)

tjr

  • Guest
Re: Xrecord.Data Max Length
« Reply #8 on: January 24, 2009, 01:26:23 AM »
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?

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8659
  • AKA Daniel
Re: Xrecord.Data Max Length
« Reply #9 on: January 24, 2009, 10:02:05 AM »
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

tjr

  • Guest
Re: Xrecord.Data Max Length
« Reply #10 on: January 24, 2009, 10:54:54 AM »
Thanks Dan, you saved my hide.

I will peruse the code and hopefully come up with a solution.