Существует ли стандартная техника для упаковки двоичных данных в строку UTF-16?

Это может быть полезно. Он реализует чистое решение C с помощью sscanf.

https://github.com/luismartingil/per.scripts/tree/master/c_parse_http_url

It использует

// Parsing the tmp_source char*
if (sscanf(tmp_source, "http://%99[^:]:%i/%199[^\n]", ip, &port, page) == 3) { succ_parsing = 1;}
else if (sscanf(tmp_source, "http://%99[^/]/%199[^\n]", ip, page) == 2) { succ_parsing = 1;}
else if (sscanf(tmp_source, "http://%99[^:]:%i[^\n]", ip, &port) == 2) { succ_parsing = 1;}
else if (sscanf(tmp_source, "http://%99[^\n]", ip) == 1) { succ_parsing = 1;}
(...)

10
задан 16 revs 24 February 2015 в 02:14
поделиться

6 ответов

Я наткнулся на Base16k после прочтения вашего вопроса. Не совсем стандартно, но, похоже, работает хорошо и было достаточно просто реализовать в C #.

5
ответ дан 3 December 2019 в 17:22
поделиться

Я могу предложить, чтобы Вы действительно использовали base64? Это не может быть самый эффективный способ сделать это storagewise, но это действительно обладает своими преимуществами:

  1. Ваше беспокойство о коде закончено.
  2. У Вас будет наименьшее количество проблем совместимости с другими плеерами, если будет кто-либо.
  3. Если закодированную строку когда-либо рассматривают как ASCII во время преобразования, экспорта, импорта, резервного копирования, восстановления, безотносительно, у Вас не будет проблем также.
  4. Если Вы когда-либо падаете замертво или заканчиваете под шиной или чем-то, любой программист, который когда-либо достает поле комментария, будет немедленно знать, что это - base64, и не предполагают, что это все шифруется или что-то.
12
ответ дан 3 December 2019 в 17:22
поделиться

Во-первых, помните, что Unicode не означает 16 битов. Факт та Система. Строка использует UTF-16, внутренне ни здесь, ни там. Символы Unicode абстрактны - они только получают разрядные представления через кодировку.

Вы говорите, что "моим устройством хранения данных является Система. Строка" - если это так, Вы не можете говорить о битах и байтах, только символы Unicode. Система. Строка, конечно, имеет свое собственное внутреннее кодирование, но (в теории), который мог отличаться.

Кстати, если Вы полагаете что внутреннее представление Системы. Строка слишком неэффективна памятью для Base64-закодированных данных, почему Вы не также вызывающий беспокойство о латинских/Западных строках?

Если Вы хотите хранить двоичные данные в Системе. Строка, Вам нужно отображение между наборами битов и символов.

Опция A: существует предварительно сделанный в форме кодирования Base64. Как Вы указали, это кодирует шесть битов данных на символ.

Опция B: Если Вы захотите упаковать больше битов на символ, то необходимо будет сделать массив (или кодирующий) 128, 256, 512, и т.д. символы Unicode, и упаковывать 7, 8, 9, и т.д. биты данных на символ. Те символы должны быть реальными символами Unicode.

Отвечать на Ваш вопрос просто, да там - стандарт, он Base64-кодирует.

Действительно ли это - настоящая проблема? У Вас есть данные перфекта для поддержки идеи не использования Base64?

3
ответ дан 3 December 2019 в 17:22
поделиться

Вы могли рассматривать двоичные данные как UTF-8b. Кодирование UTF-8b предполагает, что байты являются многобайтовыми последовательностями UTF-8, но имеет кодирование нейтрализации для вещей, которые не являются.

2
ответ дан 3 December 2019 в 17:22
поделиться

Я дурачился с прямыми массивами символов и Вашими провальными патронажными работами с моей реализацией. Код был протестирован хорошо: также - Ваши тесты сначала.

Вы могли ускорить это при помощи небезопасного кода. Но я уверен, что UnicodeEncoding так же, как медленный (если не медленнее).

/// <summary>
/// Represents an encoding that packs bytes tightly into a string.
/// </summary>
public class ByteEncoding : Encoding
{
    /// <summary>
    /// Gets the Byte Encoding instance.
    /// </summary>
    public static readonly Encoding Encoding = new ByteEncoding();

    private ByteEncoding()
    {
    }

    public override int GetBytes(char[] chars, int charIndex, int charCount, byte[] bytes, int byteIndex)
    {
        for (int i = 0; i < chars.Length; i++)
        {
            // Work out some indicies.
            int j = i * 2;
            int k = byteIndex + j;

            // Get the bytes.
            byte[] packedBytes = BitConverter.GetBytes((short) chars[charIndex + i]);

            // Unpack them.
            bytes[k] = packedBytes[0];
            bytes[k + 1] = packedBytes[1];
        }

        return chars.Length * 2;
    }

    public override int GetChars(byte[] bytes, int byteIndex, int byteCount, char[] chars, int charIndex)
    {
        for (int i = 0; i < byteCount; i += 2)
        {
            // Work out some indicies.
            int j = i / 2;
            int k = byteIndex + i;

            // Make sure we don't read too many bytes.
            byte byteB = 0;
            if (i + 1 < byteCount)
            {
                byteB = bytes[k + 1];
            }

            // Add it to the array.
            chars[charIndex + j] = (char) BitConverter.ToInt16(new byte[] { bytes[k], byteB }, 0);
        }

        return (byteCount / 2) + (byteCount % 2); // Round up.
    }

    public override int GetByteCount(char[] chars, int index, int count)
    {
        return count * 2;
    }

    public override int GetCharCount(byte[] bytes, int index, int count)
    {
        return (count / 2) + (count % 2);
    }

    public override int GetMaxByteCount(int charCount)
    {
        return charCount * 2;
    }

    public override int GetMaxCharCount(int byteCount)
    {
        return (byteCount / 2) + (byteCount % 2);
    }
}

Вот некоторый тестовый код:

    static void Main(string[] args)
    {
        byte[] original = new byte[256];

        // Note that we can't tell on the decode side how
        // long the array was if the original length is
        // an odd number. This will result in an
        // inconclusive result.
        for (int i = 0; i < original.Length; i++)
            original[i] = (byte) Math.Abs(i - 1);

        string packed = ByteEncoding.Encoding.GetString(original);
        byte[] unpacked = ByteEncoding.Encoding.GetBytes(packed);

        bool pass = true;

        if (original.Length != unpacked.Length)
        {
            Console.WriteLine("Inconclusive: Lengths differ.");
            pass = false;
        }

        int min = Math.Min(original.Length, unpacked.Length);
        for (int i = 0; i < min; i++)
        {
            if (original[i] != unpacked[i])
            {
                Console.WriteLine("Fail: Invalid at a position {0}.", i);
                pass = false;
            }
        }

        Console.WriteLine(pass ? "All Passed" : "Failure Present");

        Console.ReadLine();
    }

Тестовые работы, но Вы оказываетесь перед необходимостью тестировать его со своей API-функцией.

0
ответ дан 3 December 2019 в 17:22
поделиться

Существует другой способ работать вокруг этого ограничения: хотя я не уверен, как хорошо это работало бы.

Во-первых, необходимо будет выяснить, какую строку вызов API ожидает - и какова структура этой строки. Если я беру простой пример, позволяет, рассматривают строку .NET:

  • Int32 _length;
  • байт [] _data;
  • байт _terminator = 0;

Добавьте перегрузку к своему вызову API, таким образом:

[DllImport("legacy.dll")]
private static extern void MyLegacyFunction(byte[] data);

[DllImport("legacy.dll")]
private static extern void MyLegacyFunction(string comment);

Затем, когда необходимо назвать версию байта, можно сделать следующее:

    public static void TheLegacyWisperer(byte[] data)
    {
        byte[] realData = new byte[data.Length + 4 /* _length */ + 1 /* _terminator */ ];
        byte[] lengthBytes = BitConverter.GetBytes(data.Length);
        Array.Copy(lengthBytes, realData, 4);
        Array.Copy(data, 0, realData, 4, data.Length);
        // realData[end] is equal to 0 in any case.
        MyLegacyFunction(realData);
    }
0
ответ дан 3 December 2019 в 17:22
поделиться
Другие вопросы по тегам:

Похожие вопросы: