2010-02-19 56 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