Help - ReadData()

Just starting out? Need help? Post your questions and find answers here.
TerryHough
Enthusiast
Enthusiast
Posts: 781
Joined: Fri Apr 25, 2003 6:51 pm
Location: NC, USA
Contact:

Help - ReadData()

Post by TerryHough »

I have a file created in another language consisting of multiple 700 byte
records.

I need to read each record into a sting in order to do some manipulation.
But, ReadString() doesn't work because the record contains null bytes.

So, I guess I can use ReadData() to get the 700 bytes into memory.

How can I then get that data into a string where I can use it.

Any code example will be appreciated.

TIA
Terry
User avatar
tinman
PureBasic Expert
PureBasic Expert
Posts: 1102
Joined: Sat Apr 26, 2003 4:56 pm
Location: Level 5 of Robot Hell
Contact:

Re: Help - ReadData()

Post by tinman »

TerryHough wrote:So, I guess I can use ReadData() to get the 700 bytes into memory.

How can I then get that data into a string where I can use it.

Any code example will be appreciated.
Something like this would work:

Code: Select all

Dim buffer.b(700)
; Open file etc
ReadData(@buffer(), 700)
my_string.s = PeekS(@buffer(offset), length)
However, without specific details about these 700 bytes you'll have to work out the offset (start position within the 700 bytes of the string you want) and length (number of characters to read, or if you know the strings are all NULL terminated you can miss this out) yourself.
If you paint your butt blue and glue the hole shut you just themed your ass but lost the functionality.
(WinXPhSP3 PB5.20b14)
TerryHough
Enthusiast
Enthusiast
Posts: 781
Joined: Fri Apr 25, 2003 6:51 pm
Location: NC, USA
Contact:

Re: Help - ReadData()

Post by TerryHough »

Thanks for your reply and your idea is good, but it does not solve my
problem.
tinman wrote:

Code: Select all

Dim buffer.b(700)
; Open file etc
ReadData(@buffer(), 700)
my_string.s = PeekS(@buffer(offset), length)
I really need to get the entire 700 bytes into a string defined as 700
bytes long.

ReadData(@buffer(), 700) appears to stop at the first hex 00 (Nul) which
is at position 297.

I would have expected that of my_string.s = ReadString(), but not ReadData(....)

Even a For...Next loop using ReadByte() and trying to put the Nul value
into the string fails for me.

I know that a string containing Nul values is probably foreign to PB since
it uses it as the string delimiter. But in my case, Nul values appear in the
string because it has Binary Coded Decimal fields embedded. They
almost always have up to 7 $00 (Hex 00) positions. I have to be able
to read these fields in order to interpret them. So far I am failing evey
attempt.

Thanks for your efforts, and let me know if you have a different idea.

Terry
Berikco
Administrator
Administrator
Posts: 1326
Joined: Wed Apr 23, 2003 7:57 pm
Location: Belgium
Contact:

Post by Berikco »

you can't use strings for binary data
use structures or just reserve some memory
Maybe take a look at this viewtopic.php?t=2396
TerryHough
Enthusiast
Enthusiast
Posts: 781
Joined: Fri Apr 25, 2003 6:51 pm
Location: NC, USA
Contact:

Post by TerryHough »

Berikco wrote:you can't use strings for binary data
use structures or just reserve some memory
Maybe take a look at this viewtopic.php?t=2396
@ Berikco

I tried looking at that post earlier, but it runs together on my screen so
badly that I could not follow it. Apparently Fangles did not use the Code
tags originally. Is ther anyway to modify it to be more readable?

I appreciate your suggestion and will give it a try immediately.

Thanks,
Terry
Berikco
Administrator
Administrator
Posts: 1326
Joined: Wed Apr 23, 2003 7:57 pm
Location: Belgium
Contact:

Post by Berikco »

It's a post restored from old forum, so no code tags.
Copy/paste it first in Word or WordPad, works fine
El_Choni
TailBite Expert
TailBite Expert
Posts: 1007
Joined: Fri Apr 25, 2003 6:09 pm
Location: Spain

Post by El_Choni »

ReadData works ok, but you must translate those BCD to ASCII before using PeekS.
El_Choni
TerryHough
Enthusiast
Enthusiast
Posts: 781
Joined: Fri Apr 25, 2003 6:51 pm
Location: NC, USA
Contact:

Post by TerryHough »

@ Berikco
Thanks, got it. That will help I hope.

@ El_Choni
You wrote
ReadData works ok, but you must translate those BCD to ASCII before using PeekS.
It probably works OK, but so far I haven't been successful getting to
the actual data in those fields. :?:

For example, I know that position 296 - 303 of the 700 byte record
contains a BCD field. In hex it contains 1553000000000043 which
represents a value of 155.30. If it were negative it would contain
15530000000000C3 to represent -155.30.

I must be doing something wrong since I haven't gotten more than the
first two bytes myself. Guess I will keep on working.

Thanks for your reply and any advice.

Terry
El_Choni
TailBite Expert
TailBite Expert
Posts: 1007
Joined: Fri Apr 25, 2003 6:09 pm
Location: Spain

Post by El_Choni »

Now I see you're using a byte array... Have you tested using a memory block? With AllocateMemory(0, 700)?
El_Choni
TerryHough
Enthusiast
Enthusiast
Posts: 781
Joined: Fri Apr 25, 2003 6:51 pm
Location: NC, USA
Contact:

Post by TerryHough »

I have used both a byte array and a structure. Currently I am using a
structure after reading Berikco's thread.

Code: Select all

 ReadData(@recbuf, 700)                ; Read record to buffer
Still the same results. I swear it appears that ReadData stops when it
hits the first NUL byte.

I will see what I can do with AllocateMemory.

Thanks,
Terry
Berikco
Administrator
Administrator
Posts: 1326
Joined: Wed Apr 23, 2003 7:57 pm
Location: Belgium
Contact:

Post by Berikco »

TerryHough wrote:I have used both a byte array and a structure. Currently I am using a
structure after reading Berikco's thread.

Code: Select all

 ReadData(@recbuf, 700)                ; Read record to buffer
Still the same results. I swear it appears that ReadData stops when it
hits the first NUL byte.

I will see what I can do with AllocateMemory.

Thanks,
Terry
I dont think so, just put this line after the ReadData()

Code: Select all

Debug Loc()
TerryHough
Enthusiast
Enthusiast
Posts: 781
Joined: Fri Apr 25, 2003 6:51 pm
Location: NC, USA
Contact:

Post by TerryHough »

@ Berikco

Good thing I said "it appears" ! :oops:

You are right, of course, all of the bytes are being read in OK.

I am just having trouble handling these fields. I'm off to find a
working way to convert these BCD fields to floats. I must have
done something wrong there.

Thanks,
Terry
freak
PureBasic Team
PureBasic Team
Posts: 5948
Joined: Fri Apr 25, 2003 5:21 pm
Location: Germany

Post by freak »

Hmm, if i'm not wrong, you don't need floats here, as BCD numbers are
only whole numbers.

Somethink like this should make a normal Number out of a byte stores in BCD:

Code: Select all

BCD.l = PeekB(...) & $FF;  read byte out of memory and make it unsigned
DecimalNumber.l = (BCD >> 4)*10 + (BCD & $F) ; convert to usual format
BCD just means, that each digit of a decimal number is stored in 4 bits,
so one byte in BCD can hold numbers from 0-99 (2 digits, which use 4 bits)

Hope this helps... (tell me, if not :wink: )

Timo
quidquid Latine dictum sit altum videtur
TerryHough
Enthusiast
Enthusiast
Posts: 781
Joined: Fri Apr 25, 2003 6:51 pm
Location: NC, USA
Contact:

Post by TerryHough »

freak wrote:Hmm, if i'm not wrong, you don't need floats here, as BCD numbers are
only whole numbers.
--- snip ----
BCD just means, that each digit of a decimal number is stored in 4 bits,
so one byte in BCD can hold numbers from 0-99 (2 digits, which use 4 bits)

Hope this helps... (tell me, if not :wink: )
Thanks for your reply Freak!

I can's speak for all languages or standards but at least in the language
I have been writing in for over 20 years BCD fields are not limited to
whole numbers.

BCD fields are not limited to one byte. And the final byte of the field
carries the sign and number of significan places to the left of the
decimal. The length of the BCD field is determined by the number of
digits of precision desired. For example, an 8 byte BCD field would
allow 14 digits of precision. The precision is controlled by a program
global parameter specifing the number of digits of precision from 4 to
14.

Example shown as 8 Hex bytes:
32 64 12 34 00 00 00 00 44
represents the real number 3264.1234 since the last byte shows the value
to be postive and the decimal position is after the 4th position.
12 35 45 00 00 00 00 00 43
represents the real number 123.45

This language does math using these "real" BCD numbers completely
accurately. (Don't ask me how, I don't know. I just know is absolutely
reliable!)

Since I primarily write financial applications this is very
important to me. I must be able to store the actual values.

Again an example: A = 1 / 3 results in .333333333333333 which stores
as in Hex 33 33 33 33 33 33 33 33 40
B = 25 / 2 results in 12.5 stored as in Hex 12 50 00 00 00 00 00 42

A typical float value in PB only can approximate that, right?

For financial apps, that means I can store values up to
$999,999,999,999.99 in 8 bytes

This BCD representation allows me to accurately store numbers in
the same amount of space that a PB float value takes. But, try storing
123.45 in a float, and then get that exact value back.

My current project (hopefull can be done in PB) requires me to use
data created and stored by that language, so I must be able to "translate"
these BCD fields accurately. I am almost there, but ran into a slight
hitch (see post viewtopic.php?t=6524 for
details) that prevents more than 10 digits of precision. :(

If you have any ideas, please let me know. And thanks for your usual
great ideas and suggestions on the forum.

Terry
freak
PureBasic Team
PureBasic Team
Posts: 5948
Joined: Fri Apr 25, 2003 5:21 pm
Location: Germany

Post by freak »

See, that's why i said "Hmm, if i'm not wrong..." :wink:
I have only been in contact with BCD numbers once, and that were
whole, single-byte number. But hey, I never stop learning....

Based on your description, i wrote this one:

Code: Select all

Procedure.f BCD2Float(Memory.l, Length.l)
  DefType.l decimal, digit, divisor, addition
  DefType.f Result
  
  decimal = PeekB(Memory+Length-1) & %111111
  
  For digit = 1 To decimal
    Result * 10
    If digit & 1
      addition = (PeekB(Memory+(digit/2)) >> 4) 
    Else
      addition = (PeekB(Memory+(digit/2)-1) & $F)
    EndIf
    Result + addition
  Next digit
  
  divisor.l = 1
  For digit = decimal+1 To (Length-1)*2
    divisor * 10
    If digit & 1
      addition = (PeekB(Memory+(digit/2)) >> 4) 
    Else
      addition = (PeekB(Memory+(digit/2)-1) & $F)
    EndIf
    Result + addition / divisor
  Next digit
  
  If PeekB(Memory+Length-1) & %10000000
    Result * (-1)
  EndIf
  
  ProcedureReturn Result
EndProcedure


Debug BCD2Float(?Number1, 8)
Debug BCD2Float(?Number2, 8)
Debug BCD2Float(?Number3, 8)
Debug BCD2Float(?Number4, 8)

DataSection
  Number1: Data.b $32, $64, $12, $34, $00, $00, $00, $44 ; 3264.1234 
  Number2: Data.b $12, $35, $45, $00, $00, $00, $00, $43 ; 123.45 
  Number3: Data.b $33, $33, $33, $33, $33, $33, $33, $40 ; 1/3
  Number4: Data.b $12, $50, $00, $00, $00, $00, $00, $42 ; 25/2
EndDataSection
You pass this procedure the Memory address of a BCD number, and
the length in bytes of it. However, as you can see in the examples, it is
not very accurate. I'm trying to make it somehow better.

Timo
quidquid Latine dictum sit altum videtur
Post Reply