Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can IStreamWrapper work with istream? #918

Closed
shierei opened this issue Mar 31, 2017 · 3 comments
Closed

Can IStreamWrapper work with istream? #918

shierei opened this issue Mar 31, 2017 · 3 comments
Labels

Comments

@shierei
Copy link

shierei commented Mar 31, 2017

I am trying to parse a JSON document in a FastCGI request body. FastCGI allows you to read in the request body using istream cin. The IStreamWrapper document says the following:

IStreamWrapper wraps any class drived from std::istream, such as std::istringstream, std::stringstream, std::ifstream, std::fstream, into RapidJSON's input stream.

Can I do the following?

IStreamWrapper isw(cin);
Document d;
d.ParseStream(ism);

It compiles but it does not seem to work, at least in the FastCGI context. It hits the following assert.

include/rapidjson/reader.h:769: void rapidjson::GenericReader<SourceEncoding, TargetEncoding, StackAllocator>::ParseNull(InputStream &, Handler &) [with parseFlags = 0U, InputStream = rapidjson::BasicIStreamWrapper<std::basic_istream<char, std::char_traits>>, Handler = rapidjson::GenericDocument<rapidjson::UTF8, rapidjson::MemoryPoolAllocatorrapidjson::CrtAllocator, rapidjson::CrtAllocator>, SourceEncoding = rapidjson::UTF8, TargetEncoding = rapidjson::UTF8, StackAllocator = rapidjson::CrtAllocator]: Assertion `is.Peek() == 'n'' failed.

The call stack is as follows:

#0 0x0000003d54a32625 in raise () from /lib64/libc.so.6
#1 0x0000003d54a33e05 in abort () from /lib64/libc.so.6
#2 0x0000003d54a2b74e in __assert_fail_base () from /lib64/libc.so.6
#3 0x0000003d54a2b810 in __assert_fail () from /lib64/libc.so.6
#4 0x00000000004b1280 in rapidjson::GenericReader<rapidjson::UTF8, rapidjson::UTF8, rapidjson::CrtAllocator>::ParseNull (this=0x7fff1a7ed008,
is=..., handler=...)
at rapidjson/reader.h:769
#5 0x00000000004b1161 in rapidjson::GenericReader<rapidjson::UTF8, rapidjson::UTF8, rapidjson::CrtAllocator>::ParseValue (this=0x7fff1a7ed008,
is=..., handler=...)
at rapidjson/reader.h:1465
#6 0x00000000004aea98 in rapidjson::GenericReader<rapidjson::UTF8, rapidjson::UTF8, rapidjson::CrtAllocator>::Parse (this=0x7fff1a7ed008, is=...,
handler=...)
at rapidjson/reader.h:487
#7 0x00000000004adb82 in rapidjson::GenericDocument<rapidjson::UTF8, rapidjson::MemoryPoolAllocatorrapidjson::CrtAllocator, rapidjson::CrtAllocator>::ParseStream (this=0x7fff5255df58, is=...)
at rapidjson/document.h:2209
#8 0x00000000004ada57 in rapidjson::GenericDocument<rapidjson::UTF8, rapidjson::MemoryPoolAllocatorrapidjson::CrtAllocator, rapidjson::CrtAllocator>::ParseStream (this=0x7fff5255df58, is=...)
at rapidjson/document.h:2235

@OlafvdSpek
Copy link

Try to reduce the test case..

@miloyip
Copy link
Collaborator

miloyip commented May 3, 2017

I tried and it worked with std::cin.

#include "rapidjson/document.h"
#include "rapidjson/istreamwrapper.h"
#include <iostream>

int main() {
    rapidjson::IStreamWrapper isw(std::cin);
    rapidjson::Document d;
    std::cout << "Parse: " << (d.ParseStream(isw).HasParseError() ? "Error" : "Ok") << std::endl;
}
$ g++ -I ~/github/rapidjson/include a.cpp 
$ echo "{}" | ./a.out
Parse: Ok
$ echo "[1,2]" | ./a.out
Parse: Ok
$ echo "[1,2,]" | ./a.out
Parse: Error
$ 

@shierei
Copy link
Author

shierei commented May 3, 2017

Hi Milo,

Thanks for trying this out. In my case, it failed probably because of the particularity of how fcgi_streambuf works. I worked around this problem by slightly modifying the FileReadSteam class to work with std::cin.

class InputReadStream {
public:
  typedef char Ch;    // Character type (byte) - needed as a template type
  
  InputReadStream(char* buffer, size_t bufferSize, size_t clen) : 
    clen_(clen), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), 
    current_(buffer_), readCount_(0), count_(0), eof_(false) 
  { 
    Read();
  }

  Ch Peek() const { return *current_; }
  Ch Take() { Ch c = *current_; Read(); return c; }
  size_t Tell() const 
  { return count_ + static_cast<size_t>(current_ - buffer_); }

  // Not implemented
  void Put(Ch) { RAPIDJSON_ASSERT(false); }
  void Flush() { RAPIDJSON_ASSERT(false); } 
  Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
  size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }

  // For encoding detection only.
  const Ch* Peek4() const 
  {
    return (current_ + 4 <= bufferLast_) ? current_ : 0;
  }

private:
  void Read() 
  {
    if (current_ < bufferLast_)
      ++current_;
    else if (!eof_) 
    {
      readCount_ = min(bufferSize_, clen_ - count_);
      cin.read(buffer_, readCount_);
      bufferLast_ = buffer_ + readCount_ - 1;
      current_ = buffer_;
      count_ += readCount_;
      if (readCount_ < bufferSize_) 
      {
        buffer_[readCount_] = '\0';
        ++bufferLast_;
        eof_ = true;
      }
    }
  }

  Ch *buffer_;
  size_t bufferSize_;
  Ch *bufferLast_;
  Ch *current_;
  size_t readCount_;
  size_t count_;     // Number of characters read
  size_t clen_;
  bool eof_;
};

@shierei shierei closed this as completed May 3, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants