diff --git a/src/ScriptEngine.HostedScript/Library/Binary/BinaryDataBuffer.cs b/src/ScriptEngine.HostedScript/Library/Binary/BinaryDataBuffer.cs
index f11bf92f3..ed1374880 100644
--- a/src/ScriptEngine.HostedScript/Library/Binary/BinaryDataBuffer.cs
+++ b/src/ScriptEngine.HostedScript/Library/Binary/BinaryDataBuffer.cs
@@ -97,11 +97,7 @@ public override void SetIndexedValue(IValue index, IValue val)
///
/// Булево (Boolean)
[ContextProperty("ТолькоЧтение", "ReadOnly")]
- public bool ReadOnly
- {
- get { return _readOnly; }
-
- }
+ public bool ReadOnly => _readOnly;
///
///
@@ -521,27 +517,121 @@ public ulong ReadInt64(int position, IValue byteOrder = null)
///
- /// Разделить буфер на части по заданному разделителю.
- ///
- /// НЕ РЕАЛИЗОВАН
+ /// Разделить буфер на части по заданному разделителю или массиву разделителей.
///
///
- ///
- ///
- /// По двоичному буферу
- ///
- ///
///
/// Разделитель.
///
- ///
+ /// Массив из буферов двоичных данных
///
[ContextMethod("Разделить", "Split")]
- public IValue Split(IValue separator)
+ public ArrayImpl Split(IValue separator)
{
- throw new NotImplementedException();
+ var buffers = ParseParam(separator);
+
+ // Функция поиска требует, чтобы буферы были в порядке убывания размера
+ buffers.Sort((a, b) => b._buffer.LongLength.CompareTo(a._buffer.LongLength));
+ return SplitBuffer(buffers.ToArray());
+ }
+
+ private static List ParseParam(IValue separator)
+ {
+ var rawSeparator = separator?.GetRawValue();
+ switch (rawSeparator)
+ {
+ case BinaryDataBuffer buffer:
+ return new List { CheckedBuffer(buffer) };
+
+ case ArrayImpl array:
+ {
+ var buffers = new List();
+
+ foreach (var element in array)
+ {
+ buffers.AddRange(ParseParam(element));
+ }
+
+ return buffers;
+ }
+
+ default:
+ throw RuntimeException.InvalidArgumentType();
+ }
+ }
+
+ private static BinaryDataBuffer CheckedBuffer(BinaryDataBuffer buffer)
+ {
+ if (buffer.Size == 0)
+ {
+ throw RuntimeException.InvalidArgumentValue();
+ }
+
+ return buffer;
+ }
+
+ private ArrayImpl SplitBuffer(BinaryDataBuffer[] splitter)
+ {
+ var result = new List();
+ long start = 0;
+ var foundPosition = FindFirst(splitter, start);
+ while (foundPosition.pos != -1)
+ {
+ var length = foundPosition.pos - start;
+ result.Add(new BinaryDataBuffer(Copy(start, length), ByteOrder));
+ start = foundPosition.pos + foundPosition.buffer.Size;
+ foundPosition = FindFirst(splitter, start);
+ }
+
+ // хвостовой элемент
+ result.Add(new BinaryDataBuffer(Copy(start, _buffer.LongLength - start)));
+ return new ArrayImpl(result);
+ }
+
+ ///
+ /// Ищет ближайшее вхождение любого из буферов. Если на одной позиции находятся два и более буфера, берется бОльший.
+ ///
+ /// Массив искомых буферов
+ /// Начальная позиция поиска
+ /// Буфер и позиция или null, если нет вхождений
+ private (BinaryDataBuffer buffer, long pos) FindFirst(BinaryDataBuffer[] buffers, long start)
+ {
+ var maxI = Size - buffers[buffers.Length - 1].Size;
+ for (var i = start; i < maxI; i++)
+ {
+ foreach (var expectedBuffer in buffers)
+ {
+ if (SubsequenceEquals(_buffer, i, expectedBuffer._buffer))
+ {
+ return (expectedBuffer, i);
+ }
+ }
+ }
+
+ return (null, -1);
+ }
+
+ private byte[] Copy(long start, long length)
+ {
+ if (length == 0) return Array.Empty();
+ var partition = new byte[length];
+ Array.Copy(_buffer, start, partition, 0, length);
+ return partition;
}
+ private static bool SubsequenceEquals(byte[] sequence, long start, byte[] subsequence)
+ {
+ for (long j = 0; j < subsequence.LongLength; j++)
+ {
+ if (subsequence[j] != sequence[start + j])
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
///
///
/// Создает копию массива.
diff --git a/tests/binary-objects.os b/tests/binary-objects.os
index 130fc076a..aa5bc3a01 100644
--- a/tests/binary-objects.os
+++ b/tests/binary-objects.os
@@ -11,6 +11,7 @@
ВсеТесты = Новый Массив;
ВсеТесты.Добавить("ТестДолжен_ПроверитьЧтоСоздаетсяБуферДвоичныхДанных");
+ ВсеТесты.Добавить("ТестДолжен_ПроверитьРазделениеБуфераДвоичныхДанныхНесколькимиБуферами");
ВсеТесты.Добавить("ТестДолжен_ПроверитьЧтоМожноЗаписатьБайты");
ВсеТесты.Добавить("ТестДолжен_ПроверитьЧтоМожноПрочитатьБайты");
ВсеТесты.Добавить("ТестДолжен_ПроверитьЧтоМожноЗаписатьПрочитатьЦелое16");
@@ -30,6 +31,8 @@
ВсеТесты.Добавить("ТестДолжен_ПроверитьЧтоМетодОткрытьПотокДляЧтенияВозвращаетПотокТолькоДляЧтения");
ВсеТесты.Добавить("ТестДолжен_ПроверитьЧтоХешированиеРаботаетСПотоком");
ВсеТесты.Добавить("ТестДолжен_ПроверитьЧтоХешированиеРаботаетСДвоичнымиДанными");
+
+ ВсеТесты.Добавить("ТестДолжен_ПроверитьРазделениеБуфераДвоичныхДанныхОднимБуфером");
Возврат ВсеТесты;
@@ -351,3 +354,58 @@
НРег(ПолучитьHexСтрокуИзДвоичныхДанных(Хеширование.ХешСумма)));
КонецПроцедуры
+
+Процедура ТестДолжен_ПроверитьРазделениеБуфераДвоичныхДанныхОднимБуфером() Экспорт
+
+ Подстроки = Новый Массив;
+ Подстроки.Добавить("Часть1");
+ Подстроки.Добавить("Часть2");
+ Подстроки.Добавить("Часть3");
+ РазделительТекстом = "123";
+
+ ТестовыйБуфер = ПолучитьБуферДвоичныхДанныхИзСтроки(СтрСоединить(Подстроки, РазделительТекстом));
+ Разделитель = ПолучитьБуферДвоичныхДанныхИзСтроки(РазделительТекстом);
+
+ РазделенныеДанные = ТестовыйБуфер.Разделить(Разделитель);
+
+ юТест.ПроверитьРавенство(РазделенныеДанные.Количество(), 3, "два разделителя - три элемента");
+
+ Для Инд = 0 По Подстроки.ВГраница() Цикл
+
+ СтрокаИзБуфера = ПолучитьСтрокуИзБуфераДвоичныхДанных(РазделенныеДанные[Инд]);
+ юТест.ПроверитьРавенство(СтрокаИзБуфера, Подстроки[Инд], "сравнение строк после разделения буфера");
+
+ КонецЦикла;
+
+КонецПроцедуры
+
+Процедура ТестДолжен_ПроверитьРазделениеБуфераДвоичныхДанныхНесколькимиБуферами() Экспорт
+
+ Подстроки = Новый Массив;
+ Подстроки.Добавить("Часть1");
+ Подстроки.Добавить("Часть2");
+ Подстроки.Добавить("Часть3");
+ Подстроки.Добавить("Часть4");
+ Подстроки.Добавить("Часть5");
+
+ ТестоваяСтрока = "Часть1\R\R\NЧасть2\R\NЧасть3\NЧасть4\RЧасть5";
+
+ ТестовыйБуфер = ПолучитьБуферДвоичныхДанныхИзСтроки(ТестоваяСтрока);
+ Разделители = Новый Массив;
+ Разделители.Добавить(ПолучитьБуферДвоичныхДанныхИзСтроки("\N"));
+ Разделители.Добавить(ПолучитьБуферДвоичныхДанныхИзСтроки("\R\N"));
+ Разделители.Добавить(ПолучитьБуферДвоичныхДанныхИзСтроки("\R"));
+ Разделители.Добавить(ПолучитьБуферДвоичныхДанныхИзСтроки("\R\R\N"));
+
+ РазделенныеДанные = ТестовыйБуфер.Разделить(Разделители);
+
+ юТест.ПроверитьРавенство(РазделенныеДанные.Количество(), 5);
+
+ Для Инд = 0 По РазделенныеДанные.ВГраница() Цикл
+
+ СтрокаИзБуфера = ПолучитьСтрокуИзБуфераДвоичныхДанных(РазделенныеДанные[Инд]);
+ юТест.ПроверитьРавенство(СтрокаИзБуфера, Подстроки[Инд], "сравнение строк после разделения буфера");
+
+ КонецЦикла;
+
+КонецПроцедуры