11

I am using open_memstream in a library of mine, but I would like to port this library to MSVC. It seems there are no equivalent function available, but is there something similar enough?

What open_memstream does is it takes a char** destination and size and returns a FILE* which you many write to, the data is stored in a dynamically allocated buffer (accessible from the char** argument). When closing the FILE the char** contains the data that was written to the stream. This makes an easy way to construct large and complex string streams.

While it is possible to both read and seek from the memstream I only write to it.

Is there a way to open a similar memory FILE stream in MSVC? Also, this is pure C, no C++.

Kate Gregory
  • 18,808
  • 8
  • 56
  • 85
ext
  • 2,593
  • 4
  • 32
  • 45
  • I did notice BSD has a function called funopen which allows you to create a custom stream by setting callbacks, maybe there is something similar for MSVC? – ext May 19 '10 at 09:52

2 Answers2

4

A similar function on Windows would be CreateStreamOnHGlobal(). That however works with the IStream COM interface, it isn't a drop-in replacement for FILE. You might want to take a peek at the Cygwin source code to see what they did.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • Cygwin seems to use newlib runtime library, which implements it's own FILE structure and thus implements fopencookie (and open_memstream). At least that's what I find in the source. – ext May 19 '10 at 13:24
  • Yes, that's not unlikely. It would have to know that the FILE* references a non-file type resource. If you don't want to use Cygwin then you're kinda doomed to replace your memory stream code. – Hans Passant May 19 '10 at 13:56
4

https://github.com/Snaipe/fmem is a wrapper for different platform/version specific equivalents of open_memstream

It tries in sequence the following implementations:

  • open_memstream.
  • fopencookie, with growing dynamic buffer.
  • funopen, with growing dynamic buffer.
  • WinAPI temporary memory-backed file.

When no other mean is available, fmem falls back to tmpfile()

maxirmx
  • 185
  • 1
  • 10
  • This is a great answer honestly, and the linked library is pretty good too. (Although personally I would focus less on providing a common wrapper interface for all available fallbacks and more on providing polyfill `open_memstream` implementations. I think `fopencookie` and `funopen` can basically be used to create an `open_memstream`. I haven't thought through the Windows side of things. But if you're willing to go through undefined behavior in your polyfills, you can actually implement `fmemopen` on some platforms by opening a dummy file (including `/dev/null`) and using `setvbuf`.) – mtraceur Oct 28 '21 at 19:02
  • (A key point about abusing `setvbuf` to implement `fmemopen` is that undefined behavior is extremely bad practice in *general code*, but totally justified fair game in polyfills that backport functionality to specific old platforms, because you can just publish the assumptions that polyfill depends on, and leave it to the user of the old/nonstandard system to figure out if that polyfill implementation works for them, which is where the responsibility for providing polyfills ultimately lies.) – mtraceur Oct 28 '21 at 19:07
  • I mention `fmemopen` (and how to polyfill it on platforms where you can make certain assumptions) for two reasons. One is that if you have a reasonable upper-bound, `open_memstream` functionality, and this can be a polyfill that's good enough in some cases. If someone is happy to use the fmem library (and thus change their code) they might also be happy to make a smaller change and use `fmemopen` instead of `open_memstream` in situations where they know an upper bound that's not too large on the contents of their "file". The second is that (cont) – mtraceur Oct 28 '21 at 19:22
  • it was another example of the general point that I was making with `open_menstream` and polyfilling - I think sometimes it's better to just code with the API you want, and then tell the user "if this API does not exist on your system, figure out how to polyfill it well enough for this code, because it's a great API and we're all improverished if we can't write code that just relies on that API to be there". And this answer and the linked library are doubly great precisely because they show at least two ways that you could implement a polyfill of `open_memstream`. – mtraceur Oct 28 '21 at 19:26
  • @mtraceur, thank you for your comments If you consider porting very complex project (like this one [metanorma](https://github.com/tamatebako/metanorma) ) where you have a dependency on a small but unique library that uses a call to open_memstream then you would probably have to adopt some kind of polyfill. – maxirmx Nov 01 '21 at 07:38