[Include] BRW - Binary reader and writer for PAWN
#1

BRW (Binary Reader and Writer)


Overall, the I/O file functions that the file.inc provides seem to be really powerful and I haven't seen an include that supports reading binary files utilizing them. This include allows you read and write binary data using various data types.


Features:
  • Endianness: Supports little endian and big endian formats.
  • Supports jumping from one position to another position relative to (start, current position and end of file).
  • Allows you to read and write signed and unsigned data types.
  • Allows you write and read 4-byte floating point values (IEEE 754).



Functions:


PHP код:
// Returns a valid handle.
     
BRWBRW::Open(const filename[], fmode:BRW::typeEndianness:format little_endianbool:append false);
 
         
Endianness:
            - 
little_endian
            
big_endian
            
         fmode
:
            - 
bin_read
            
bin_write
//Closes a handle that was previously opened and returns the number of bytes read or written:
    
BRW::Close(BRW:handle);
//Jumps to a specific location in the file using a certain offset.
    
BRW::Seek(BRW:handleoffsetseek_whencewhence seek_start);
          
seek_whence
             
-  seek_start //start of the file
             
-  seek_current //current position in the file
             
-  seek_end //end of the file
//Skips a certain number of bytes relative to the current position in the file:
    
BRW::Skip(BRW:handlenumber_of_bytes); 
Reading:

Values can either be retrieved: called-by-reference or returned. The value returned or called-by-reference is converted to a PAWN cell (4-bytes). Each time a function is called, the specific amount of bytes each data type holds are advanced on the file, e.g, INT16 will advance 2 bytes.

PHP код:

//Signed INT8 (signed byte)
BRW::ReadInt8(BRW:handle, &int8 0); //Range [-127, 127]
BRW::ReadSByte(BRW:handle, &int8 0); //Range [-127, 127]
//Unsigned INT8(unsigned byte)
BRW::ReadUInt8(BRW:handle, &uint8 0); //Range [0, 255]
BRW::ReadUByte(BRW:handle, &uint8 0); //Range [0, 255]
//Signed INT16 / Unsigned INT 16
BRW::ReadInt16(BRW:handle, &int16 0); //Range [-32767, 32767]
BRW::ReadUInt16(BRW:handle, &uint16 0); //Range [0, 65535]
//Signed INT32 / Unsigned INT32 (doesn't support values greater than 0x7FFFFFFF - if greater, prints a warning with the value in HEX)
BRW::ReadInt32(BRW:handle, &int32 0); //Range [-2147483647, 2147483647]
BRW::ReadUInt32(BRW:handle, &uint32 0); 
//PAWN cell array (4 bytes)
BRW::ReadCells(BRW:handlebuffer[], maxlen sizeof(buffer)); //Range [-2147483647, 2147483647]
//4-byte floating point
Float:BRW::ReadFloat(BRW:handle, &Float:value BRW_FLOAT_NAN
Writing:

The input values are PAWN cells that are converted to the specific amount of bytes each data type holds, the values must be bound by the ranges for each data type. Each time a function is called, the specific amount of bytes each data type holds are advanced on the file, e.g, INT16 will advance 2 bytes.

PHP код:
//Signed INT8 (signed byte)
BRW::WriteInt8(BRW:handleint8); //Range [-127, 127]
BRW::WriteSByte(BRW:handleint8); //Range [-127, 127]
//Unsigned INT8(unsigned byte)
BRW::WriteUInt8(BRW:handleuint8); //Range [0, 255]
BRW::WriteUByte(BRW:handleuint8); //Range [0, 255]
//Signed INT16 / Unsigned INT 16
BRW::WriteInt16(BRW:handleint16); //Range [-32767, 32767]
BRW::WriteUInt16(BRW:handleuint16); //Range [0, 65535]
//Signed INT32 / Unsigned INT32 (could write values greater than 0x7FFFFFFF up to 0xFFFFFFFF but those cannot be read.)
BRW::WriteInt32(BRW:handleint32); //Range [-2147483647, 2147483647]
BRW::WriteUInt32(BRW:handleuint32)
//PAWN cell array (4 bytes)
BRW::WriteCells(BRW:handle, const buffer[], maxlen sizeof(buffer)); //Range [-2147483647, 2147483647]
//4-byte floating point
BRW::WriteFloat(BRW:handleFloat:value); 
Examples:

Reading and writing random data:

PHP код:
new const file[15] = "Binary/bin.dat";
    new 
BRW:handle BRW::Open(filebin_write);
    
//Writes a signed INT32
    
BRW::WriteInt32(handle2147483647);
    
BRW::WriteInt32(handle, -2147483647);
    
//Writes an usigned INT32 (PAWN really cannot handle numbers greater than cellmax)
    
BRW::WriteUInt32(handle9239481);
    
//Writes a signed INT16
    
BRW::WriteInt16(handle1294);
    
BRW::WriteInt16(handle, -3841);
    
//Writes an unsigned INT16
    
BRW::WriteUInt16(handle62000);
    
//Writes a signed INT8 (sbyte)
    
BRW::WriteInt8(handle127); //same function
    
BRW::WriteSByte(handle, -127);  //same function
    //Writes an usigned INT8 (unsigned byte)
    
BRW::WriteUInt8(handle255); //same function
    
BRW::WriteUByte(handle255);  //same function
    //writes a 4-byte floating point 
    
BRW::WriteFloat(handle234.23444);
    
BRW::WriteFloat(handle, -32.133);
    
//Writes a PAWN cell array
    
new cells[4] = {2344912939931283874129394};
    
BRW::WriteCells(handlecells);
    
printf("Bytes written: %d bytes."BRW::Close(handle));
    
handle BRW::Open(filebin_read);
    
printf("%d"BRW::ReadInt32(handle));
    
printf("%d"BRW::ReadInt32(handle));
    
printf("%d"BRW::ReadUInt32(handle));
    
printf("%d"BRW::ReadInt16(handle));
    
printf("%d"BRW::ReadInt16(handle));
    
printf("%d"BRW::ReadUInt16(handle));
    
printf("%d"BRW::ReadInt8(handle));
    
printf("%d"BRW::ReadSByte(handle));
    
printf("%d"BRW::ReadUInt8(handle));
    
printf("%d"BRW::ReadUByte(handle));
    
printf("%f"BRW::ReadFloat(handle));
    
printf("%f"BRW::ReadFloat(handle));
    new 
dest[4];
    
BRW::ReadCells(handledestsizeof(dest));
    for(new 
0sizeof(dest); i++)
        
printf("dest[%d] = %d"idest[i]);
    
printf("Bytes read: %d bytes."BRW::Close(handle)); 
Outputs:

Код:
Bytes written: 46 bytes.
2147483647
-2147483647
9239481
1294
-3841
62000
127
-127
255
255
234.234436
-32.132995
dest[0] = 23449
dest[1] = 1293993
dest[2] = 1283874
dest[3] = 129394
Bytes read: 46 bytes.
Reading nodes from the Node*.dat files in the GTA SA's paths folder:

PHP код:
/*
/*
Example using BRW to read binary data contained in the GTA SA Path's folder.
Documentation to read the binary files can be found at: http://gta.wikia.com/wiki/Paths_(GTA_SA)...6.04135785
 ** Header ** 
4b - UINT32 - number of nodes (section 1)
4b - UINT32 - number of vehicle nodes (section 1a)
4b - UINT32 - number of ped nodes (section 1b)
4b - UINT32 - number of navi nodes (section 2)
4b - UINT32 - number of links (section 3/5/6)
**************************************************
** Node entry **
4b - UINT32   - Mem Address, unused
4b - UINT32   - always zero, unused
6b - INT16[3] - Position (XYZ), see below
2b - INT16    - unknown, always 0x7FFE
2b - UINT16   - Link ID
2b - UINT16   - Area ID (same as in filename)
2b - UINT16   - Node ID (increments by 1)
1b - UINT8    - Path Width
1b - UINT8    - Node Type
4b - UINT32   - Flags
*/
#include <a_samp>
#include <BRW>
/* Sizes in Bytes */
#define HEADER_SIZE                 (20)
#define PATH_NODE_ENTRY_SIZE         (28)
#define NAVI_NODE_ENTRY_SIZE        (14)
#define LINK_ENTRY_SIZE                (4)
main()
{
    new const 
filename[24] = "Paths/NODES21.dat";
    new 
Float:xFloat:yFloat:zlinkidareaidnodetype;
    const 
nodeid 23;
    
printf("Path node: \n");
    
ReadPathNode(filenamenodeidxyzlinkidareaidnodetype);
    
printf("nodeid: %d | areaid: %d | linkid: %d | type: %d | pos(%f, %f, %f)"nodeidareaidlinkidnodetypexyz);
}
stock ReadPathNode(const filename[], nodeid, &Float:x, &Float:y, &Float:z, &linkid, &areaid, &nodetype)
{
    new 
BRWhandle BRW::Open(filenamebin_read); //The default endianness is: Little endian.
    //Offsets
    #define POSITION_OFFSET            8 //relative to the start of each node entry
    /********************************/
    
new totalnodes BRW::ReadUInt32(handle);
    if(
nodeid >= totalnodes)
    {
        
printf("ERROR: Invalid nodeid. The max node index is %d."totalnodes 1);
        
BRW::Close(handle);
        return 
0;
    }
    
BRW::Seek(handleHEADER_SIZE + (PATH_NODE_ENTRY_SIZE nodeid) + POSITION_OFFSETseek_start); //Position the file on the nodeid's entry relative to the start of the file.
    
floatdiv(float(BRW::ReadInt16(handle)), 8.0);
    
floatdiv(float(BRW::ReadInt16(handle)), 8.0);
    
floatdiv(float(BRW::ReadInt16(handle)), 8.0);
    
BRW::Seek(handle2seek_current); //skip 2 bytes | could have used BRW::Skip(handle, 2);
    
linkid BRW::ReadUInt16(handle);
    
areaid BRW::ReadUInt16(handle);
    
BRW::Seek(handle3seek_current); //skip 3 bytes (nodeid and path width) could have used BRW::Skip(handle, 3);
    
nodetype BRW::ReadInt8(handle); //Unsigned INT8 (byte)
    
BRW::Close(handle);
    return 
1;

Download:

Github
Examples


Feel free to report any bugs or provide some suggestions or feedback!
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)