2010-02-19 19 views
2

我试图用istringstream从某个内存重新创建编码的wstring。内存布局如下:使用istringstream处理可变长度的内存块

  1. 1个字节表示wstring编码的开始。任意这是'!'。
  2. n个字节以文本格式存储字符串的字符长度,例如, 0X31,0x32,0x33将是“123”,即,123个字符的字符串
  3. 1个字节分离器(空格字符)
  4. n个字节,其是构成该串,其中的wchar_t的各自2个字节的wchars 。

例如,该字节序列:

21 36 20 66 00 6F 00 6F 00

是 “6 f.o.o.!” (使用点来表示字符0)

我得到的只是一个char *指针(我们称之为pData),以此编码数据在其中的内存块的开始。使用数据重建wstring(“foo”)的最佳方法是什么,并且还会将指针移到编码数据末尾的下一个字节?

我正在使用istringstream来允许我使用前缀字节,字符串长度和分隔符。之后,我可以计算读取多少字节并使用流的read()函数插入适当调整大小的wstring。 问题是,如何首先将此内存放入istringstream中? I 可能先尝试构造一个字符串,然后将其传递到istringstream,例如,

std::string s((const char*)pData); 

但这不起作用,因为字符串在第一个空字节处被截断。或者,我可以用字符串的其他构造函数来明确说明有多少字节使用:

std::string s((const char*)pData, len); 

它的工作原理,但只有我知道什么是len事前。鉴于数据是可变长度的,这很棘手。

这似乎是一个真正可解决的问题。我的菜鸟状态是否意味着我忽略了一个简单的解决方案?或者我用整个字符串方法吠叫错误的树?

回答

0

尝试设置你的stringstream的rdbuf

char* buffer = something; 
std::stringbuf *pbuf; 
std::stringstream ss; 

std::pbuf=ss.rdbuf(); 
std::pbuf->sputn(buffer, bufferlength); 
// use your ss 

编辑:我看到这个解决方案将有类似的问题,以你的字符串(字符*,LEN)的情况。你能告诉我们更多关于你的缓冲区对象吗?如果你不知道这个长度,并且它没有被终止,它将会很难处理。

+0

没有缓冲“对象”我很害怕,只是一个指向内存中的BLOB 。我得到了一个指向该内存开始的指针,我需要(重新)从它创建一个wstring。我不能真正终止任何事情,因为空值是有效的数据(请参阅我的示例)。我有点知道它的大小,因为它是用数据编码的,尽管它是一个文本字符串。作为一个人,我可以很容易地解析这些数据,但我正在努力想出一种在代码中实现的优雅方式。如果您有任何具体的问题想要了解,请提出问题。 – WalderFrey 2010-02-19 14:26:21

0

是否可以修改如何对长度进行编码,并使其具有固定的大小?

unsigned long size = 6; // known string length
char* buffer = new char[1 + sizeof(unsigned long) + 1 + size];
buffer[0] = '!';
memcpy(buffer+1, &size, sizeof(unsigned long));

缓冲器应当保持开始指示符(1个字节),实际的大小(无符号长的大小),定界符(1个字节)和文本本身(size)。
通过这种方式,您可以轻松获得“漂亮”的大小,然后将指针指向超出开销的位置,然后在字符串构造函数中使用len变量。
unsigned long len;
memcpy(&len, pData+1, sizeof(unsigned long)); // +1 to avoid the start indicator
// len now contains 6
char* actualData = pData + 1 + sizeof(unsigned long) + 1;
std::string s(actualData, len);

它低的水平,而且容易出错:)(例如,如果你读什么,是不是编码,你希望它是,该LEN可以得到相当大的方式),但你避免动态读取字符串的长度。

0

这看起来似乎该订单上应该工作:

std::wstring make_string(char const *input) { 
    if (*input != '!') 
     return ""; 
    char length = *++input; 
    return std::wstring(++input, length); 
} 

困难的部分是处理的大小可变长度。如果没有指定长度的东西,很难猜测何时停止将数据视为指定字符串的长度。

至于移动指针,如果你打算在函数内部做,你需要传递指针的引用,否则这是一个简单的问题,你可以将你发现的大小添加到指针中接收。

0

人们很容易(AB)使用(不建议使用,但尽管如此标准)的std :: istrstream这里:

// Maximum size to read is 
// 1 for the exclamation mark 
// Digits for the character count (digits10() + 1) 
// 1 for the space 
const std::streamsize max_size = 3 + std::numeric_limits<std::size_t>::digits10; 

std::istrstream s(buf, max_size); 

if (std::istream::traits_type::to_char_type(s.get()) != '!'){ 
    throw "missing exclamation"; 
} 

std::size_t size; 
s >> size; 

if (std::istream::traits_type::to_char_type(s.get()) != ' '){ 
    throw "missing space"; 
} 

std::wstring(reinterpret_cast<wchar_t*>(s.rdbuf()->str()), size/sizeof(wchar_t)); 
+0

有意思......所以你说,因为我不知道数据的大小,所以我将流设置为最大值。是的,我想这会工作。这会引入额外的开销吗? – WalderFrey 2010-02-19 15:03:17

+0

@WalderFrey:istrstream不拥有它的缓冲区,并且不做任何复制。 – 2010-02-19 15:12:45

+0

但是考虑两次,传递max可能不是一个好主意,因为流的实现可能最终会使用类似buf + size的东西来计算缓冲区的末端,如果buf是一个很大的值,它可能会溢出。我会更新答案以使用更安全的缓冲区大小。 – 2010-02-19 15:15:10