Skip to content

Commit e3c9033

Browse files
committed
feat(extensions): 添加字节序转换扩展方法
为 byte[]、Span<byte> 和 ReadOnlySpan<byte> 添加字节序转换功能: - ConvertEndianInPlace/ConvertEndian: 按指定单元字节长度转换字节序 - ConvertEndianByInt16/Int32/Int64: 按固定字节单元转换 - BigEndianToLittleEndian/LittleEndianToBigEndian: 大小端互转
1 parent faaa8b4 commit e3c9033

3 files changed

Lines changed: 313 additions & 1 deletion

File tree

GameFrameX.Foundation.Extensions/ByteExtensions.cs

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,170 @@ public static void Reverse(this byte[] bytes, int index, int length)
378378
Array.Reverse(bytes, index, length);
379379
}
380380

381+
/// <summary>
382+
/// 按指定单元字节长度就地转换字节数组的字节序。
383+
/// </summary>
384+
/// <param name="bytes">要转换的字节数组。</param>
385+
/// <param name="elementSize">每个数据单元的字节长度。</param>
386+
/// <exception cref="ArgumentNullException">当 <paramref name="bytes"/> 为 null 时抛出。</exception>
387+
/// <exception cref="ArgumentOutOfRangeException">当 <paramref name="elementSize"/> 小于 1 时抛出。</exception>
388+
/// <exception cref="ArgumentException">当数组长度不能被 <paramref name="elementSize"/> 整除时抛出。</exception>
389+
public static void ConvertEndianInPlace(this byte[] bytes, int elementSize)
390+
{
391+
ArgumentNullException.ThrowIfNull(bytes, nameof(bytes));
392+
bytes.AsSpan().ConvertEndianInPlace(elementSize);
393+
}
394+
395+
/// <summary>
396+
/// 按指定单元字节长度就地转换字节数组指定范围的字节序。
397+
/// </summary>
398+
/// <param name="bytes">要转换的字节数组。</param>
399+
/// <param name="offset">开始转换的偏移量。</param>
400+
/// <param name="length">要转换的字节数。</param>
401+
/// <param name="elementSize">每个数据单元的字节长度。</param>
402+
/// <exception cref="ArgumentNullException">当 <paramref name="bytes"/> 为 null 时抛出。</exception>
403+
/// <exception cref="ArgumentOutOfRangeException">当 <paramref name="offset"/>、<paramref name="length"/> 或 <paramref name="elementSize"/> 非法时抛出。</exception>
404+
/// <exception cref="ArgumentException">当范围越界或长度不能被 <paramref name="elementSize"/> 整除时抛出。</exception>
405+
public static void ConvertEndianInPlace(this byte[] bytes, int offset, int length, int elementSize)
406+
{
407+
ArgumentNullException.ThrowIfNull(bytes, nameof(bytes));
408+
ArgumentOutOfRangeException.ThrowIfNegative(offset, nameof(offset));
409+
ArgumentOutOfRangeException.ThrowIfNegative(length, nameof(length));
410+
411+
if (offset + length > bytes.Length)
412+
{
413+
throw new ArgumentException(LocalizationService.GetString(LocalizationKeys.Exceptions.IndexCountExceedBufferLength, bytes.Length, offset, length), nameof(length));
414+
}
415+
416+
bytes.AsSpan(offset, length).ConvertEndianInPlace(elementSize);
417+
}
418+
419+
/// <summary>
420+
/// 按指定单元字节长度转换字节数组的字节序,并返回新数组。
421+
/// </summary>
422+
/// <param name="bytes">要转换的字节数组。</param>
423+
/// <param name="elementSize">每个数据单元的字节长度。</param>
424+
/// <returns>转换后的新字节数组。</returns>
425+
/// <exception cref="ArgumentNullException">当 <paramref name="bytes"/> 为 null 时抛出。</exception>
426+
/// <exception cref="ArgumentOutOfRangeException">当 <paramref name="elementSize"/> 小于 1 时抛出。</exception>
427+
/// <exception cref="ArgumentException">当数组长度不能被 <paramref name="elementSize"/> 整除时抛出。</exception>
428+
public static byte[] ConvertEndian(this byte[] bytes, int elementSize)
429+
{
430+
ArgumentNullException.ThrowIfNull(bytes, nameof(bytes));
431+
432+
var result = new byte[bytes.Length];
433+
bytes.CopyTo(result, 0);
434+
result.ConvertEndianInPlace(elementSize);
435+
return result;
436+
}
437+
438+
/// <summary>
439+
/// 按指定单元字节长度转换字节数组指定范围的字节序,并返回新数组。
440+
/// </summary>
441+
/// <param name="bytes">要转换的字节数组。</param>
442+
/// <param name="offset">开始转换的偏移量。</param>
443+
/// <param name="length">要转换的字节数。</param>
444+
/// <param name="elementSize">每个数据单元的字节长度。</param>
445+
/// <returns>转换后的新字节数组。</returns>
446+
/// <exception cref="ArgumentNullException">当 <paramref name="bytes"/> 为 null 时抛出。</exception>
447+
/// <exception cref="ArgumentOutOfRangeException">当 <paramref name="offset"/>、<paramref name="length"/> 或 <paramref name="elementSize"/> 非法时抛出。</exception>
448+
/// <exception cref="ArgumentException">当范围越界或长度不能被 <paramref name="elementSize"/> 整除时抛出。</exception>
449+
public static byte[] ConvertEndian(this byte[] bytes, int offset, int length, int elementSize)
450+
{
451+
ArgumentNullException.ThrowIfNull(bytes, nameof(bytes));
452+
ArgumentOutOfRangeException.ThrowIfNegative(offset, nameof(offset));
453+
ArgumentOutOfRangeException.ThrowIfNegative(length, nameof(length));
454+
455+
if (offset + length > bytes.Length)
456+
{
457+
throw new ArgumentException(LocalizationService.GetString(LocalizationKeys.Exceptions.IndexCountExceedBufferLength, bytes.Length, offset, length), nameof(length));
458+
}
459+
460+
var result = new byte[length];
461+
Array.Copy(bytes, offset, result, 0, length);
462+
result.ConvertEndianInPlace(elementSize);
463+
return result;
464+
}
465+
466+
/// <summary>
467+
/// 按 2 字节单元就地转换字节数组的字节序。
468+
/// </summary>
469+
/// <param name="bytes">要转换的字节数组。</param>
470+
public static void ConvertEndianByInt16InPlace(this byte[] bytes)
471+
{
472+
bytes.ConvertEndianInPlace(ConstBaseTypeSize.ShortSize);
473+
}
474+
475+
/// <summary>
476+
/// 按 4 字节单元就地转换字节数组的字节序。
477+
/// </summary>
478+
/// <param name="bytes">要转换的字节数组。</param>
479+
public static void ConvertEndianByInt32InPlace(this byte[] bytes)
480+
{
481+
bytes.ConvertEndianInPlace(ConstBaseTypeSize.IntSize);
482+
}
483+
484+
/// <summary>
485+
/// 按 8 字节单元就地转换字节数组的字节序。
486+
/// </summary>
487+
/// <param name="bytes">要转换的字节数组。</param>
488+
public static void ConvertEndianByInt64InPlace(this byte[] bytes)
489+
{
490+
bytes.ConvertEndianInPlace(ConstBaseTypeSize.LongSize);
491+
}
492+
493+
/// <summary>
494+
/// 按 2 字节单元转换字节数组的字节序,并返回新数组。
495+
/// </summary>
496+
/// <param name="bytes">要转换的字节数组。</param>
497+
/// <returns>转换后的新字节数组。</returns>
498+
public static byte[] ConvertEndianByInt16(this byte[] bytes)
499+
{
500+
return bytes.ConvertEndian(ConstBaseTypeSize.ShortSize);
501+
}
502+
503+
/// <summary>
504+
/// 按 4 字节单元转换字节数组的字节序,并返回新数组。
505+
/// </summary>
506+
/// <param name="bytes">要转换的字节数组。</param>
507+
/// <returns>转换后的新字节数组。</returns>
508+
public static byte[] ConvertEndianByInt32(this byte[] bytes)
509+
{
510+
return bytes.ConvertEndian(ConstBaseTypeSize.IntSize);
511+
}
512+
513+
/// <summary>
514+
/// 按 8 字节单元转换字节数组的字节序,并返回新数组。
515+
/// </summary>
516+
/// <param name="bytes">要转换的字节数组。</param>
517+
/// <returns>转换后的新字节数组。</returns>
518+
public static byte[] ConvertEndianByInt64(this byte[] bytes)
519+
{
520+
return bytes.ConvertEndian(ConstBaseTypeSize.LongSize);
521+
}
522+
523+
/// <summary>
524+
/// 将大端字节序数据转换为小端字节序数据,并返回新数组。
525+
/// </summary>
526+
/// <param name="bytes">要转换的字节数组。</param>
527+
/// <param name="elementSize">每个数据单元的字节长度。</param>
528+
/// <returns>转换后的小端字节序数组。</returns>
529+
public static byte[] BigEndianToLittleEndian(this byte[] bytes, int elementSize)
530+
{
531+
return bytes.ConvertEndian(elementSize);
532+
}
533+
534+
/// <summary>
535+
/// 将小端字节序数据转换为大端字节序数据,并返回新数组。
536+
/// </summary>
537+
/// <param name="bytes">要转换的字节数组。</param>
538+
/// <param name="elementSize">每个数据单元的字节长度。</param>
539+
/// <returns>转换后的大端字节序数组。</returns>
540+
public static byte[] LittleEndianToBigEndian(this byte[] bytes, int elementSize)
541+
{
542+
return bytes.ConvertEndian(elementSize);
543+
}
544+
381545
/// <summary>
382546
/// 将字节数组转换为Base64字符串。
383547
/// </summary>

GameFrameX.Foundation.Extensions/ReadOnlySpanExtensions.cs

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -428,4 +428,78 @@ public static double ReadDoubleLittleEndianValue(this ReadOnlySpan<byte> buffer,
428428
offset += ConstBaseTypeSize.DoubleSize;
429429
return value;
430430
}
431-
}
431+
432+
/// <summary>
433+
/// 按指定单元字节长度转换只读字节跨度的字节序,并返回新数组。
434+
/// </summary>
435+
/// <param name="buffer">要转换的只读字节跨度。</param>
436+
/// <param name="elementSize">每个数据单元的字节长度。</param>
437+
/// <returns>转换后的新字节数组。</returns>
438+
/// <exception cref="ArgumentOutOfRangeException">当 <paramref name="elementSize"/> 小于 1 时抛出。</exception>
439+
/// <exception cref="ArgumentException">当长度不能被 <paramref name="elementSize"/> 整除时抛出。</exception>
440+
public static byte[] ConvertEndian(this ReadOnlySpan<byte> buffer, int elementSize)
441+
{
442+
ArgumentOutOfRangeException.ThrowIfLessThan(elementSize, 1, nameof(elementSize));
443+
444+
if (buffer.Length % elementSize != 0)
445+
{
446+
throw new ArgumentException(LocalizationService.GetString(LocalizationKeys.Exceptions.OffsetCountExceedBufferLength, buffer.Length, 0, buffer.Length), nameof(buffer));
447+
}
448+
449+
var result = buffer.ToArray();
450+
result.AsSpan().ConvertEndianInPlace(elementSize);
451+
return result;
452+
}
453+
454+
/// <summary>
455+
/// 按 2 字节单元转换只读字节跨度的字节序,并返回新数组。
456+
/// </summary>
457+
/// <param name="buffer">要转换的只读字节跨度。</param>
458+
/// <returns>转换后的新字节数组。</returns>
459+
public static byte[] ConvertEndianByInt16(this ReadOnlySpan<byte> buffer)
460+
{
461+
return buffer.ConvertEndian(ConstBaseTypeSize.ShortSize);
462+
}
463+
464+
/// <summary>
465+
/// 按 4 字节单元转换只读字节跨度的字节序,并返回新数组。
466+
/// </summary>
467+
/// <param name="buffer">要转换的只读字节跨度。</param>
468+
/// <returns>转换后的新字节数组。</returns>
469+
public static byte[] ConvertEndianByInt32(this ReadOnlySpan<byte> buffer)
470+
{
471+
return buffer.ConvertEndian(ConstBaseTypeSize.IntSize);
472+
}
473+
474+
/// <summary>
475+
/// 按 8 字节单元转换只读字节跨度的字节序,并返回新数组。
476+
/// </summary>
477+
/// <param name="buffer">要转换的只读字节跨度。</param>
478+
/// <returns>转换后的新字节数组。</returns>
479+
public static byte[] ConvertEndianByInt64(this ReadOnlySpan<byte> buffer)
480+
{
481+
return buffer.ConvertEndian(ConstBaseTypeSize.LongSize);
482+
}
483+
484+
/// <summary>
485+
/// 将大端字节序数据转换为小端字节序数据,并返回新数组。
486+
/// </summary>
487+
/// <param name="buffer">要转换的只读字节跨度。</param>
488+
/// <param name="elementSize">每个数据单元的字节长度。</param>
489+
/// <returns>转换后的小端字节序数组。</returns>
490+
public static byte[] BigEndianToLittleEndian(this ReadOnlySpan<byte> buffer, int elementSize)
491+
{
492+
return buffer.ConvertEndian(elementSize);
493+
}
494+
495+
/// <summary>
496+
/// 将小端字节序数据转换为大端字节序数据,并返回新数组。
497+
/// </summary>
498+
/// <param name="buffer">要转换的只读字节跨度。</param>
499+
/// <param name="elementSize">每个数据单元的字节长度。</param>
500+
/// <returns>转换后的大端字节序数组。</returns>
501+
public static byte[] LittleEndianToBigEndian(this ReadOnlySpan<byte> buffer, int elementSize)
502+
{
503+
return buffer.ConvertEndian(elementSize);
504+
}
505+
}

GameFrameX.Foundation.Extensions/SpanExtensions.cs

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,4 +226,78 @@ public static bool ReadBoolValue(this Span<byte> buffer, ref int offset)
226226
offset += ConstBaseTypeSize.BoolSize;
227227
return value;
228228
}
229+
230+
/// <summary>
231+
/// 按指定单元字节长度就地转换字节跨度的字节序。
232+
/// </summary>
233+
/// <param name="buffer">要转换的字节跨度。</param>
234+
/// <param name="elementSize">每个数据单元的字节长度。</param>
235+
/// <exception cref="ArgumentOutOfRangeException">当 <paramref name="elementSize"/> 小于 1 时抛出。</exception>
236+
/// <exception cref="ArgumentException">当长度不能被 <paramref name="elementSize"/> 整除时抛出。</exception>
237+
public static void ConvertEndianInPlace(this Span<byte> buffer, int elementSize)
238+
{
239+
ArgumentOutOfRangeException.ThrowIfLessThan(elementSize, 1, nameof(elementSize));
240+
241+
if (buffer.Length <= 1 || elementSize == 1)
242+
{
243+
return;
244+
}
245+
246+
if (buffer.Length % elementSize != 0)
247+
{
248+
throw new ArgumentException(LocalizationService.GetString(LocalizationKeys.Exceptions.OffsetCountExceedBufferLength, buffer.Length, 0, buffer.Length), nameof(buffer));
249+
}
250+
251+
for (var i = 0; i < buffer.Length; i += elementSize)
252+
{
253+
buffer.Slice(i, elementSize).Reverse();
254+
}
255+
}
256+
257+
/// <summary>
258+
/// 按 2 字节单元就地转换字节跨度的字节序。
259+
/// </summary>
260+
/// <param name="buffer">要转换的字节跨度。</param>
261+
public static void ConvertEndianByInt16InPlace(this Span<byte> buffer)
262+
{
263+
buffer.ConvertEndianInPlace(ConstBaseTypeSize.ShortSize);
264+
}
265+
266+
/// <summary>
267+
/// 按 4 字节单元就地转换字节跨度的字节序。
268+
/// </summary>
269+
/// <param name="buffer">要转换的字节跨度。</param>
270+
public static void ConvertEndianByInt32InPlace(this Span<byte> buffer)
271+
{
272+
buffer.ConvertEndianInPlace(ConstBaseTypeSize.IntSize);
273+
}
274+
275+
/// <summary>
276+
/// 按 8 字节单元就地转换字节跨度的字节序。
277+
/// </summary>
278+
/// <param name="buffer">要转换的字节跨度。</param>
279+
public static void ConvertEndianByInt64InPlace(this Span<byte> buffer)
280+
{
281+
buffer.ConvertEndianInPlace(ConstBaseTypeSize.LongSize);
282+
}
283+
284+
/// <summary>
285+
/// 将大端字节序数据就地转换为小端字节序数据。
286+
/// </summary>
287+
/// <param name="buffer">要转换的字节跨度。</param>
288+
/// <param name="elementSize">每个数据单元的字节长度。</param>
289+
public static void BigEndianToLittleEndianInPlace(this Span<byte> buffer, int elementSize)
290+
{
291+
buffer.ConvertEndianInPlace(elementSize);
292+
}
293+
294+
/// <summary>
295+
/// 将小端字节序数据就地转换为大端字节序数据。
296+
/// </summary>
297+
/// <param name="buffer">要转换的字节跨度。</param>
298+
/// <param name="elementSize">每个数据单元的字节长度。</param>
299+
public static void LittleEndianToBigEndianInPlace(this Span<byte> buffer, int elementSize)
300+
{
301+
buffer.ConvertEndianInPlace(elementSize);
302+
}
229303
}

0 commit comments

Comments
 (0)