String created from buffer has wrong length and strip() result is incorrect
ketmar via Digitalmars-d-learn
digitalmars-d-learn at puremagic.com
Fri Oct 17 17:50:49 PDT 2014
On Sat, 18 Oct 2014 00:32:09 +0000
Lucas Burson via Digitalmars-d-learn
<digitalmars-d-learn at puremagic.com> wrote:
> On Friday, 17 October 2014 at 17:40:09 UTC, ketmar via
> Digitalmars-d-learn wrote:
>
> > i developed a habit of making such buffers one byte bigger than
> > necessary and just setting the last byte to 0 before
> > converting. this
> > way it's guaranteed to be 0-terminated.
>
> Perfect, great idea. Below is my utility method to pull strings
> out of a buffer.
>
>
> /**
> * Get a string from buffer where the string spans [offset_start,
> offset_end).
> * Params:
> * buffer = Buffer with an ASCII string to obtain.
> * offset_start = Beginning byte offset within the buffer
> where the string starts.
> * offset_end = Ending byte offset which is not included in
> the string.
> */
> string bufferGetString(ubyte[] buffer, ulong offset_start, ulong
> offset_end)
> in
> {
> assert(buffer != null);
> assert(offset_start < offset_end);
> assert(offset_end <= buffer.length);
> }
> body
> {
> ulong bufflen = offset_end - offset_start;
>
> // add one to the lenth for null-termination
> ubyte[] temp = new ubyte[bufflen+1];
> temp[0..bufflen] = buffer[offset_start..offset_end];
> temp[bufflen] = '\0';
>
> return strip(to!string(cast(const char*) temp.ptr));
> }
>
> unittest
> {
> ubyte[] no_null = [' ', 'A', 'B', 'C', ' '];
> assert("ABC" == bufferGetString(no_null, 0, no_null.length));
> assert("ABC" == bufferGetString(no_null, 1, no_null.length-1));
> assert("A" == bufferGetString(no_null, 1, 2));
> }
note that you can make your code slightly simplier (and more correct):
size_t bufflen = offset_end-offset_start;
// add one to the lenth for null-termination
auto temp = new ubyte[bufflen+1]; // compiler knows the type ;-)
temp[0..$-1] = buffer[offset_start..offset_end];
// this is not necessary, as 'temp' is initialized with zeroes
//temp[$-1] = '\0';
return strip(to!string(cast(const char*) temp.ptr));
also note that this allocates like crazy. ;-) this can be tolerable,
but good to remember anyway.
besides, slices rocks, so you can just pass a slice there. so:
string bufferGetString (const(ubyte)[] buffer) {
import std.conv : to;
import std.string : strip;
if (buffer.length == 0) return null; // or ""
if (buffer[$-1] == 0) return to!string(cast(char*)buffer.ptr).strip;
auto temp = new ubyte[](buffer.length+1);
temp[0..$-1] = buffer[];
return to!string(cast(char*)temp.ptr).strip;
}
unittest {
ubyte[] no_null = [' ', 'A', 'B', 'C', ' '];
immutable ubyte[] no_nullI = [' ', 'A', 'B', 'C', ' '];
assert("ABC" == bufferGetString(no_null[0..$]));
assert("ABC" == bufferGetString(no_null[1..$-1]));
// look, we can use const/immutable buffers too!
assert("A" == bufferGetString(no_nullI[1..2]));
}
slices are cheap, and you'll get range checking at the call site.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 181 bytes
Desc: not available
URL: <http://lists.puremagic.com/pipermail/digitalmars-d-learn/attachments/20141018/58a0ebb1/attachment-0001.sig>
More information about the Digitalmars-d-learn
mailing list