|
|
Comments and Discussions
|
|
 |

|
I received an email from Christopher and I'll post my code when it's done because now I have to concentrate in other things.
|
|
|
|

|
I am trying to solve the problem with the BLOB Binary fields but I can't solve it.
I will appreciate any help with this issue.
Thanks a lot in advance.
|
|
|
|

|
I have this data in .DB about BLOB field: 63 16 0 0 74 4 0 0 1 0 in hex is 3F 10 0 0 4A 4 0 0 1 0 if I reverse:
0 0 10 3F 0 0 4 4A 0 1
44A=1098 length of the BLOB data (type 03. suballocated ) and the index is 103F??? that is my cuestion because if I have this index it doesn't fix with the address of the fisrts data in .MB, where it is in 1150hex address.
I need any help to see the light.
Thanks a lot in advance.
|
|
|
|

|
I remember that when I followed that link for the paradox4.txt file, I googled a bit and found a pretty good C library to read paradox files. In there was code that helped mevwitg memo fields, and should have blob ad well.
Here we go, it has a function called PX_GET_DATA_BLOB.
Here is the link: http://pxlib.sourceforge.net/index.php
|
|
|
|

|
I saw that lib, I solved. The lib was realy usefull.
|
|
|
|

|
Cool! Maybe you can post your code in the comments here as well. Perhaps over time we can all develop this into a full .net library.
|
|
|
|

|
I will do when I have fully tested, but my solution is only for type 3, suballocated blob type.
|
|
|
|

|
Hi Cristopher, I am trying for two dsys to understand how to read memo field. The problem is that I do not understand how is data stored.
For example, I have a table which contains a memo field.
Record 1: memo field = "Example number 1"
Record 2: memo field = "Example number 10"
Record 3: memo field = "Example number 100"
fieldSize for each field is 11 bytes (no matter if memo field contains 1 or 100 characters).
BitConverter returns correct size of the memo string, however the byte array that is passed to GetString function always has only 1 byte (11-10).
Can anyone help me with where is the memo string actually stored? Or help me with reading memo fields, I would be very grateful.
|
|
|
|

|
First of all, this is cool library. Thank you guys.
I fought with blob too and solution for Suballocated block is below.
It is not fully error resistant but hope helps.
public byte[] ReadBlob(byte[] blobInfo)
{
if (blobInfo.Length < 10)
return null;
uint OffsetAndIndex = BitConverter.ToUInt32(blobInfo, blobInfo.Length-10); //was 0
uint index = OffsetAndIndex & 0x000000ff;
uint Offset = OffsetAndIndex & 0xffffff00;
int size = BitConverter.ToInt32(blobInfo, blobInfo.Length - 6); //was 4
int hsize = 9;
int mod_nr = BitConverter.ToInt16(blobInfo, blobInfo.Length - 2); //was 8
if (size > 0)
{
this.stream.Position = Offset;
byte[] head;
head = new byte[6];
this.reader.Read(head, 0, 3);
//first byte B
//00 - Header block
//02 - Single blob block
//03 - Suballocated block
//04 - Free block
//following short is number of 4K blocks
//based on _px_get_data_blob in paradox.c library http://pxlib.sourceforge.net/index.php
if (head[0] == 3) //Suballocated block
{
int checks = BitConverter.ToUInt16(head, 1);
byte[] rest;
rest = new byte[9];
this.reader.Read(rest, 0, 9); //read remaining 9 bytes of 12 bytes header
this.stream.Position = Offset + 12 + index * 5; //jump to blob data (header first)
this.reader.Read(head, 0, 5); //read header
if (size != ((int)head[1] - 1) * 16 + head[4])
return null; //Blob does not have expected size
byte[] blobdata;
blobdata = new byte[size];
this.stream.Position = Offset + head[0] * 16;
this.reader.Read(blobdata, 0, size);
return blobdata;
}
viliam
|
|
|
|

|
Hi Petr,
This is a great little class library. Only thing still missing from it is Memo field support but I will see if I can add it myself.
Years ago, I wrote something very similar for xBase. It was a reader/writer with memo field support. You have inspired me to put up an article about it.
I wanted to point out a bug I just found while testing against a database I have. The ParadoxFile class, GetString() method does not respect the maximum string length set by the field. Here is a fix I put in for this.
public string GetString(byte[] data, int from, int maxLength)
{
int stringLength = Array.FindIndex(data, from, b => b == 0) - from;
if (stringLength > maxLength)
stringLength = maxLength;
return Encoding.Default.GetString(data, from, stringLength);
}
UPDATE:
I have figured out how to Parse Logical types, and have a very crude Memo field read, I am embarrassed to even include it, but maybe it helps someone... Unfortunately my database only has a 1 Memofield of size 250 bytes so I can't test large memo reads.
Inside of ParadoxRecord.DateValues {get;}
case ParadoxFieldTypes.MemoBLOb:
val = _block.File.GetStringFromMemo(_block._data, (int) buff.Position, dataSize);
buff.Position += dataSize;
break;
case ParadoxFieldTypes.Logical:
val = (_block._data[(int)buff.Position] - 128) > 0;
buff.Position += dataSize;
break;
and inside of ParadoxFile
public string GetStringFromMemo(byte[] data, int from, int size)
{
var memoBufferSize = size - 10;
var memoDataBuffer = new byte[memoBufferSize];
var memoMetaData = new byte[10];
Array.Copy(data, from, memoDataBuffer, 0, memoBufferSize);
Array.Copy(data, from + memoBufferSize, memoMetaData, 0, 10);
var memoSize = BitConverter.ToInt32(memoMetaData, 4);
return GetString(memoDataBuffer, 0, memoSize);
}
modified on Sunday, January 2, 2011 5:59 AM
|
|
|
|

|
Any help with BLOB fields?
|
|
|
|

|
Cool!!!!
Your updates are so much appreciated!!
Thx
|
|
|
|

|
Thank you for the sources, I cannot test it but I believe in you This will be included in the article.
|
|
|
|

|
If from are equal to data.Length-1 then Array.FindIndex(data, from, b => b == 0) returns -1 and ArgumentOutOfRangeException will thrown in Encoding.Default.GetString().
So I use this code instead:
public string GetString(byte[] data, int from, int maxLength)
{
int stringLength;
for (stringLength = from; stringLength < data.Length
&& data[stringLength] != 0; stringLength++) ;
stringLength -= from;
if (stringLength > maxLength)
stringLength = maxLength;
return Encoding.Default.GetString(data, from, stringLength);
}
|
|
|
|

|
I have tried all possible propositions in this messages for BlobMemo and Logical, and both of them do not work as expectesd. I am curious through, I have just tried to connect using MS OleDb and Odbc drivers, and both work. Is there some gotcha that I am not aware of, so I need to use this library?
|
|
|
|

|
Hi Petr,
I have got an internal question. Is it right that last record of data block is set again in next data block?
Thx Peter
|
|
|
|

|
I don't think so, but confirm it please and if you know how to know the address of BLOB data in .MB please let me know.
|
|
|
|

|
very good job, thank you!
greetings from vienna
2 suggestions:
// Numeric values should be decoded this way:
private void ConvertBytesNum(int start, int length)
{
if ( ((byte)(this.block.data[start])&0x80)!=0)
this.block.data[start] = (byte)(this.block.data[start] &0x7F);
else if (this.block.data[start+0]==0 &&
this.block.data[start+1]==0 &&
this.block.data[start+2]==0 &&
this.block.data[start+3]==0 &&
this.block.data[start+4]==0 &&
this.block.data[start+5]==0 &&
this.block.data[start+6]==0 &&
this.block.data[start+7]==0 )
;
else for(int i=0;i<8;i++)
this.block.data[start + i] = (byte)(~(this.block.data[start + i]));
Array.Reverse(this.block.data, start, length);
}
// since ParadoxFieldTypes.Number usually is integer:
case ParadoxFieldTypes.Number:
ConvertBytesNum((int)buff.Position, dataSize);
var dbl = r.ReadDouble();
if (double.IsNaN(dbl))
val = (object)DBNull.Value;
else if (dbl == Convert.ToInt32(dbl))
val = Convert.ToInt32(dbl);
else
val = dbl;
|
|
|
|

|
Hi, I have updated my article, thank you for you suggestions, but I disagree with retyping double type to integer just because of the current value. The code using this library could count on the specific data type and returning various data types for each row and the same column could be very confusing. Petr
|
|
|
|

|
two more suggestions:
ParadoxReader.ParadoxRecord.Datavalues.get():
case ParadoxFieldTypes.Date:
ConvertBytes((int)buff.Position, dataSize);
var days = r.ReadInt32();
val = new DateTime(1, 1, 1).AddDays(days).AddDays(-1); break;
case ParadoxFieldTypes.Timestamp:
ConvertBytes((int)buff.Position, dataSize);
var ms = r.ReadDouble();
val = new DateTime(1, 1, 1).AddMilliseconds(ms).AddDays(-1);
break;
case ParadoxFieldTypes.Time:
ConvertBytes((int)buff.Position, dataSize);
val = r.ReadInt32(); break;
greetings
tonki
|
|
|
|

|
Thank you again for your suggestions
|
|
|
|

|
I see where you say you haven't implemented its structure, but do you plan to do so?
I have been trying to figure out how to pull data from a paradox database, and your project works great.
If you do not plan on doing so, can you point me in the right direction? I'd need to get blob data out too.
|
|
|
|
|

|
Any advance in the BLOB structure? I'm very interested.
Thank you.
|
|
|
|

|
I have some code which reads BLOB structures, which works in my case. I hope it helps you too. I'm not a C# developer, so it may contain some bugs...
Add this type
public delegate byte[] ReadBlobDelegate(byte[] blobInfo);
Add this field to ParadoxFile
public ReadBlobDelegate readBlob;
Add this to the DataValues property of ParadoxRecord
case ParadoxFieldTypes.BLOb:
if (this.block.file.readBlob != null) {
byte[] blobInfo;
blobInfo = new byte[dataSize];
r.Read(blobInfo, 0, dataSize);
val = this.block.file.readBlob(blobInfo);
}
else
{
val = null; buff.Position += dataSize;
}
break;
Add this field to the ParadoxTable class private readonly ParadoxBlobFile BlobFile;
Add this code to the ParadoxTable constructor
if (Path.GetFileNameWithoutExtension(file).EndsWith(".MB", StringComparison.InvariantCultureIgnoreCase) ||
Path.GetExtension(file).Equals(".MB", StringComparison.InvariantCultureIgnoreCase))
{
this.BlobFile = new ParadoxBlobFile(file);
this.readBlob = this.BlobFile.ReadBlob;
}
Add this code the the ParadoxTable dispose procedure
if (this.BlobFile != null)
{
this.BlobFile.Dispose();
}
Add this class to the ParadoxTable class
internal class ParadoxBlobFile : IDisposable
{
private readonly Stream stream;
private readonly BinaryReader reader;
public ParadoxBlobFile(string fileName)
: this(new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
}
public ParadoxBlobFile(Stream stream)
{
this.stream = stream;
this.reader = new BinaryReader(stream);
}
public virtual void Dispose()
{
this.stream.Dispose();
}
public byte[] ReadBlob(byte[] blobInfo)
{
uint OffsetAndIndex = (uint)System.Runtime.InteropServices.Marshal.ReadInt32(blobInfo, 0);
uint index = OffsetAndIndex & 0x000000ff;
uint Offset = OffsetAndIndex & 0xffffff00;
int size = System.Runtime.InteropServices.Marshal.ReadInt32(blobInfo, 4);
int hsize = 9;
int mod_nr = System.Runtime.InteropServices.Marshal.ReadInt16(blobInfo, 8);
if (size > 0)
{
this.stream.Position = Offset;
byte[] head;
head = new byte[6];
this.reader.Read(head, 0, 3);
this.reader.Read(head, 0, hsize - 3); int checkSize = System.Runtime.InteropServices.Marshal.ReadInt32(head, 0);
if (checkSize == size)
{
byte[] buffer;
buffer = new byte[size];
this.reader.Read(buffer, 0, size);
return buffer;
}
}
return null;
}
}
|
|
|
|

|
That is great, thank you very much for your code, I will include to the article for others who could use it. I cannot test it but I believe you spent enough time on this. If there will be some bugs, please let me know here. Petr
|
|
|
|

|
Minor addition to the source code: the ParadoxFieldTypes.Graphic field type also uses the ReadBlob function (at least it does in my case).
case ParadoxFieldTypes.Graphic:
case ParadoxFieldTypes.BLOb:
var blobInfo = new byte[dataSize];
r.Read(blobInfo, 0, dataSize);
val = this.block.file.ReadBlob(blobInfo);
break;
|
|
|
|
 |
|
|
General News Suggestion Question Bug Answer Joke Rant Admin
|
Read contents of a Paradox database in pure .NET code without using BDE or other libraries; index support included.
| Type | Article |
| Licence | CPOL |
| First Posted | 11 Aug 2010 |
| Views | 38,876 |
| Downloads | 1,504 |
| Bookmarked | 36 times |
|
|