Это может быть полезно. Он реализует чистое решение 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;}
(...)
Я наткнулся на Base16k после прочтения вашего вопроса. Не совсем стандартно, но, похоже, работает хорошо и было достаточно просто реализовать в C #.
Я могу предложить, чтобы Вы действительно использовали base64? Это не может быть самый эффективный способ сделать это storagewise, но это действительно обладает своими преимуществами:
Во-первых, помните, что Unicode не означает 16 битов. Факт та Система. Строка использует UTF-16, внутренне ни здесь, ни там. Символы Unicode абстрактны - они только получают разрядные представления через кодировку.
Вы говорите, что "моим устройством хранения данных является Система. Строка" - если это так, Вы не можете говорить о битах и байтах, только символы Unicode. Система. Строка, конечно, имеет свое собственное внутреннее кодирование, но (в теории), который мог отличаться.
Кстати, если Вы полагаете что внутреннее представление Системы. Строка слишком неэффективна памятью для Base64-закодированных данных, почему Вы не также вызывающий беспокойство о латинских/Западных строках?
Если Вы хотите хранить двоичные данные в Системе. Строка, Вам нужно отображение между наборами битов и символов.
Опция A: существует предварительно сделанный в форме кодирования Base64. Как Вы указали, это кодирует шесть битов данных на символ.
Опция B: Если Вы захотите упаковать больше битов на символ, то необходимо будет сделать массив (или кодирующий) 128, 256, 512, и т.д. символы Unicode, и упаковывать 7, 8, 9, и т.д. биты данных на символ. Те символы должны быть реальными символами Unicode.
Отвечать на Ваш вопрос просто, да там - стандарт, он Base64-кодирует.
Действительно ли это - настоящая проблема? У Вас есть данные перфекта для поддержки идеи не использования Base64?
Вы могли рассматривать двоичные данные как UTF-8b. Кодирование UTF-8b предполагает, что байты являются многобайтовыми последовательностями UTF-8, но имеет кодирование нейтрализации для вещей, которые не являются.
Я дурачился с прямыми массивами символов и Вашими провальными патронажными работами с моей реализацией. Код был протестирован хорошо: также - Ваши тесты сначала.
Вы могли ускорить это при помощи небезопасного кода. Но я уверен, что 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-функцией.
Существует другой способ работать вокруг этого ограничения: хотя я не уверен, как хорошо это работало бы.
Во-первых, необходимо будет выяснить, какую строку вызов API ожидает - и какова структура этой строки. Если я беру простой пример, позволяет, рассматривают строку .NET:
Добавьте перегрузку к своему вызову 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);
}