Extending functionality for working with binary data


If you wish to leave comments or ask questions, please log on or sign up.
This feature is implemented in 1C:Enterprise version 8.3.10.2168.

We are gradually increasing the functionality for working with binary data. There are several reasons for this. At the first stage, we have not implemented everything we had originally planned. Secondly, while discussing new possible features, we have received a number of requests from you that we have also decided to implement.

New functions for converting binary data into different formats

We have added many new functions that convert binary data to the global context. For example, you can implement direct and inverse conversion of binary data into a regular string, string of Base64 format and string of BinHex format. In addition, you can convert binary data into formats Base64, BinHex, and vice versa.

Similar conversions are supported for the BinaryDataBuffer type. You can convert binary data buffer into binary data and back.

Besides, two new features allow you to split binary data into several parts, and vice versa, combine multiple objects of the BinaryData type into one. The new object will then include the data of all the parts in the order that you specify.

In terms of their meaning, these functions are similar to splitting and combining of files, but in many cases, they are more efficient. This is due to the fact that you do not need to store binary data in a file in advance and because there is no unnecessary copying of data during splitting.

Enabling work with streams for the objects that work with files

Since the use of binary data is largely associated with file operations, we felt it was quite logical and commonsensical to add the functionality for working with streams to those objects that are now reading and writing files in one way or another.

As a result, you can now open streams for reading and writing when using such objects as:

  • TextReader and TextWriter
  • FastInfoSetReader and FastInfoSetWriter
  • HTMLReader and HTMLWriter
  • JSONReader and JSONWriter
  • XMLReader and XMLWriter
  • ZipFileReader and ZipFileWriter

You can get the body as a stream when working with HTTP:

  • HTTPRequest and HTTPResponse
  • HTTPServiceRequest and HTTPServiceResponse

You can write to and read from a stream when working with the objects:

  • TextDocument
  • SpreadsheetDocument
  • FormattedDocument
  • GeographicalSchema
  • GraphicalSchema
  • FTPConnection

Now you can write to a stream when you are working with the Picture and ConversionToCanonicalXML types. Besides, working with streams is now supported in different methods of the XSLTransform, CryptoManager, CryptoCertificate, and DataHashing objects.

Efficient copying using reading and writing of data

Tools for working with binary data that we implemented during the first stage allowed us to copy streams. But for large quantities of data, this operation was not very effective.

Therefore, we implemented a new CopyTo() method for the DataReader object. Not only does it eliminate this problem, but also simplifies the text, making it more understandable.

For example, in the past you could get binary data from one stream and write it into another stream.
SourceStream = FileStreams.OpenForRead(SourceFileName);
DataReader = New DataReader(SourceStream);
BinaryData = DataReader.Read().GetBinaryData();

TargetStream = FileStreams.OpenForWrite(TargetFileName);
DataWriter = New DataWriter(TargetStream);
DaraWriter.Write(BinaryData);

Now there is no need to get binary data, copying takes place already at the stage of data reading.
SourceStream = FileStreams.OpenForRead(SourceFileName);
DataReader = New DataReader(SourceStream);

TargetStream = FileStreams.OpenForWrite(TargetFileName);

DataReader.CopyTo(TargetStream);

An advantage to this method is that you can copy not only to a stream, but also to the DataWriter object. This option is useful when, in addition to the data from the source stream, you need to write your own data into the output stream.

Bitwise logical operations with the binary data buffer

Now you can use bitwise logical operations when working with binary data buffers. The result of the bitwise merging of source bytes and bytes in the specified buffer will be written into the source buffer according to the rules of the selected logical operation. We have implemented the following operations:

  • WriteBitwiseAnd()
  • WriteBitwiseOr()
  • WriteBitwiseXor()
  • WriteBitwiseAndNot()
  • Invert()

A good example of the use of bitwise logical operations is a task of parsing of retail equipment exchange format. For example, the retail equipment exchange format is described by a field that is 1 byte long. This field contains a set of attributes that describe the product type:

  • Bits 0-2: tax rate
  • Bit 3: 0 - goods sold by the piece, 1 - goods sold by weight
  • Bit 4: 0 - allow for sale, 1 - not allow for sale
  • Bit 5: 0 - allow counting, 1 - not allow counting
  • Bit 6: 0 - retail sale not allowed, 1 - retail sale is allowed
  • Bit 7: reserved

The script that retrieves this data and presents it in a form suitable for further processing might look like this.
Function DecodeProductProperties(Properties)

    MaskTaxRate     = 7;
    MaskPieces      = 8;
    MaskSaleAllowed = 16;
    MaskInferior    = 32;
    MaskCashSale    = 64;

    TaxRate = BitwiseAnd(Properties, MaskTaxRate);

    Pieces      = (BitwiseAnd(Properties, MaskPieces)      = 0);
    SaleAllowed = (BitwiseAnd(Properties, MaskSaleAllowed) = 0);
    Inferior    = (BitwiseAnd(Properties, MaskInferior)    = 0);
    CashSale    = (BitwiseAnd(Properties, MaskCashSale)    = 1);

    Result = New Structure();
    Result.Insert("TaxRate",     TaxRate);
    Result.Insert("Pieces",      Pieces);
    Result.Insert("SaleAllowed", SaleAllowed);
    Result.Insert("Inferior",    Inferior);
    Result.Insert("CashSale",    CashSale);

    Return Result;

EndFunction

Function BitwiseAnd (Byte1, Byte2)

    Buffer1 = ByteToBuffer(Byte1);
    Buffer2 = ByteToBuffer(Byte2);
    Buffer1.WriteBitwiseAnd(0, Buffer2);

    Return Buffer1[0];

EndFunction

Function ByteToBuffer(Byte)

    Buffer = New BinaryDataBuffer(1);
    Buffer[0] = Byte;

    Return Buffer;

EndFunction

Converting hexadecimal and binary literals to numbers

We have added two new features to the global context that convert hexadecimal and binary literals into numbers:

  • NumberFromHexString()
  • NumberFromBinaryString()

Binary literals are convenient for determining masks when used with bitwise operations. For example, in the previous example with parsing the retail equipment exchange format, masks are specified using decimal numbers. It is not very convenient, because when you write and read the code, you must constantly convert a decimal number into the binary system in your mind.
MaskTaxRate     = 7;
MaskPieces      = 8;
MaskSaleAllowed = 16;
MaskInferior    = 32;
MaskCashSale    = 64;

Instead, it is much more convenient to use binary literals. The script becomes more obvious and the probability of error is significantly reduced.
MaskTaxRate     = NumberFromBinaryString("0b00000111");
MaskPieces      = NumberFromBinaryString("0b00001000");
MaskSaleAllowed = NumberFromBinaryString("0b00010000");
MaskInferior    = NumberFromBinaryString("0b00100000");
MaskCashSale    = NumberFromBinaryString("0b01000000");

Hexadecimal literals are convenient for parsing technical formats: formats for images, audio, and video.

Changes in NativeAPI add-in technology

Earlier there were a number of restrictions for transferring binary data between 1C:Enterprise and add-ins. For example, sending binary data to an add-in was not possible, and if you were working in the web client, exchanging binary data was not possible at all.

Now we are planning to remove all these restrictions. You can exchange binary data both ways - and even in the web client.

It won’t affect the work of the existing add-ins. They will continue to work as before. In the newly created add-ins though, you can now pass BinaryData objects as parameters.