ChipMaster's trial hacks on C++CMS starting with v1.2.1. Not sure I'll follow on with the v2 since it looks to be breaking and mostly frivolous.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

444 lines
8.6 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (C) 2008-2012 Artyom Beilis (Tonkikh) <artyomtnk@yahoo.com>
  4. //
  5. // See accompanying file COPYING.TXT file for licensing details.
  6. //
  7. ///////////////////////////////////////////////////////////////////////////////
  8. #ifndef CPPCMS_STEAL_BUF_H
  9. #define CPPCMS_STEAL_BUF_H
  10. #include <streambuf>
  11. #include <ostream>
  12. #include <istream>
  13. #include <stdio.h>
  14. #include <string>
  15. #include <string.h>
  16. #include <stdlib.h>
  17. namespace cppcms {
  18. namespace util {
  19. ///
  20. /// Simple std::streambuf to create input from [char const *,char const *) range
  21. ///
  22. /// \ver{v1_2}
  23. class const_char_buf : public std::streambuf {
  24. public:
  25. ///
  26. /// Create Empty buffer
  27. ///
  28. const_char_buf()
  29. {
  30. range(0,0);
  31. }
  32. ///
  33. /// Create a buffer from a range
  34. ///
  35. const_char_buf(char const *begin,char const *end)
  36. {
  37. range(begin,end);
  38. }
  39. ///
  40. /// Define the range for existing buffer, pointer is reset to begin
  41. ///
  42. void range(char const *cbegin,char const *cend)
  43. {
  44. char *begin = const_cast<char*>(cbegin);
  45. char *end = const_cast<char*>(cend);
  46. setg(begin,begin,end);
  47. }
  48. ///
  49. /// Begin of range
  50. ///
  51. char const *begin() const
  52. {
  53. return eback();
  54. }
  55. ///
  56. /// End of range
  57. ///
  58. char const *end() const
  59. {
  60. return egptr();
  61. }
  62. };
  63. ///
  64. /// Simple std::istream implementation for range of [char const *,char const *)
  65. ///
  66. /// \ver{v1_2}
  67. class const_char_istream : public std::istream {
  68. public:
  69. ///
  70. /// Create new empty stream
  71. ///
  72. const_char_istream() : std::istream(0)
  73. {
  74. init(&buf_);
  75. }
  76. ///
  77. /// Create stream initialized with range [begin,end)
  78. ///
  79. const_char_istream(char const *begin,char const *end) : std::istream(0)
  80. {
  81. buf_.range(begin,end);
  82. init(&buf_);
  83. }
  84. ///
  85. /// Get begin of the range
  86. ///
  87. char const *begin() const
  88. {
  89. return buf_.begin();
  90. }
  91. ///
  92. /// Get end of the range
  93. ///
  94. char const *end() const
  95. {
  96. return buf_.end();
  97. }
  98. ///
  99. /// Set range, resets pointer to start and clears flags
  100. ///
  101. void range(char const *begin,char const *end)
  102. {
  103. buf_.range(begin,end);
  104. clear();
  105. }
  106. private:
  107. const_char_buf buf_;
  108. };
  109. ///
  110. /// \brief Very simple output stream buffer that uses stack for small chunks of
  111. /// text and then allocates memory of the default buffer is too small.
  112. ///
  113. /// It is something like std::stringbuf with small string optimization, it also
  114. /// allows to access the memory without actually creating the string itself.
  115. ///
  116. /// The template parameter defines how many characters should be allocated
  117. /// on stack by default before heap is used.
  118. ///
  119. template<size_t OnStackSize = 128>
  120. class stackbuf : public std::streambuf {
  121. stackbuf(stackbuf const &);
  122. void operator=(stackbuf const &);
  123. public:
  124. ///
  125. /// get the pointer to the beginning of the output buffer
  126. ///
  127. char *begin()
  128. {
  129. return pbase();
  130. }
  131. ///
  132. /// get the pointer to the end of the output buffer
  133. ///
  134. char *end()
  135. {
  136. return pptr();
  137. }
  138. ///
  139. /// get the 0 terminated string from the buffer.
  140. ///
  141. char *c_str()
  142. {
  143. *pptr() = 0;
  144. return begin();
  145. }
  146. ///
  147. /// get the std::string from the buffer.
  148. ///
  149. std::string str()
  150. {
  151. return std::string(begin(),size_t(end()-begin()));
  152. }
  153. stackbuf()
  154. {
  155. init();
  156. }
  157. ~stackbuf()
  158. {
  159. free(on_heap_);
  160. }
  161. protected:
  162. int overflow(int c)
  163. {
  164. size_t current_size;
  165. size_t new_size;
  166. if(pbase() == on_stack_) {
  167. current_size = OnStackSize;
  168. new_size = OnStackSize * 2;
  169. on_heap_ = (char *)malloc(new_size + 1);
  170. if(!on_heap_)
  171. throw std::bad_alloc();
  172. memcpy(on_heap_,on_stack_,current_size);
  173. }
  174. else {
  175. current_size = pptr() - pbase();
  176. new_size = current_size * 2;
  177. char *new_ptr = (char *)realloc(on_heap_,new_size + 1);
  178. if(!new_ptr)
  179. throw std::bad_alloc();
  180. on_heap_ = new_ptr;
  181. }
  182. setp(on_heap_,on_heap_ + new_size);
  183. pbump(current_size);
  184. if(c!=EOF)
  185. sputc(c);
  186. return 0;
  187. }
  188. private:
  189. void init()
  190. {
  191. on_heap_ = 0;
  192. setp(on_stack_,on_stack_+OnStackSize);
  193. }
  194. char *on_heap_;
  195. char on_stack_[OnStackSize + 1];
  196. };
  197. ///
  198. /// \brief This is a special buffer that allows to "steal" some chunk
  199. /// of text from the output stream.
  200. ///
  201. /// It does this by replacing stream's streambuf object with temporary
  202. /// stream buffer that records all data written to the stream and then
  203. /// returns the original buffer upon call to release() member function
  204. /// it steal_buffer destruction.
  205. ///
  206. /// The \a Size parameter defines the default chunk of memory allocated
  207. /// on the stack before heap is used.
  208. ///
  209. template<size_t Size = 128>
  210. class steal_buffer : public stackbuf<Size> {
  211. public:
  212. ///
  213. /// Create the buffer and "Steal" the buffer from \a out
  214. ///
  215. steal_buffer(std::ostream &out)
  216. {
  217. stolen_ = 0;
  218. stream_ = 0;
  219. steal(out);
  220. }
  221. ///
  222. /// Create an empty buffer
  223. ///
  224. steal_buffer()
  225. {
  226. stolen_ = 0;
  227. stream_ = 0;
  228. }
  229. ///
  230. /// Steal the buffer from \a out
  231. ///
  232. void steal(std::ostream &out)
  233. {
  234. release();
  235. stolen_ = out.rdbuf(this);
  236. stream_ = &out;
  237. }
  238. ///
  239. /// Release the "stolen" buffer back, now the buffer contains all
  240. /// the data that was recorded.
  241. ///
  242. void release()
  243. {
  244. if(stream_ && stolen_) {
  245. stream_->rdbuf(stolen_);
  246. }
  247. stream_ = 0;
  248. stolen_ = 0;
  249. }
  250. ~steal_buffer()
  251. {
  252. release();
  253. }
  254. private:
  255. std::streambuf *stolen_;
  256. std::ostream *stream_;
  257. };
  258. ///
  259. /// \brief Fast output stream object.
  260. ///
  261. /// This is a special ostream that uses stack in order
  262. /// to receive the data and faster then std::stringstream for
  263. /// small chunks, also it is not limited for any particular size.
  264. ///
  265. template<size_t Size = 128>
  266. class stackstream : public std::ostream {
  267. public:
  268. ///
  269. /// Create a new stackstream
  270. ///
  271. stackstream() : std::ostream(0)
  272. {
  273. rdbuf(&buf_);
  274. }
  275. ///
  276. /// Get the pointer to the first character in the range
  277. ///
  278. char *begin()
  279. {
  280. return buf_.begin();
  281. }
  282. ///
  283. /// Get the pointer to the one past last character in the range
  284. ///
  285. char *end()
  286. {
  287. return buf_.end();
  288. }
  289. ///
  290. /// Get a NUL terminated recorded string
  291. ///
  292. char *c_str()
  293. {
  294. return buf_.c_str();
  295. }
  296. ///
  297. /// Get a recorded string
  298. ///
  299. std::string str()
  300. {
  301. return buf_.str();
  302. }
  303. private:
  304. stackbuf<Size> buf_;
  305. };
  306. template<typename Filter,int BufferSize=128>
  307. class filterbuf : public std::streambuf {
  308. public:
  309. filterbuf() : output_(0), output_stream_(0)
  310. {
  311. setp(buffer_,buffer_+BufferSize);
  312. }
  313. filterbuf(std::ostream &out) : output_(0), output_stream_(0)
  314. {
  315. setp(buffer_,buffer_+BufferSize);
  316. steal(out);
  317. }
  318. ~filterbuf()
  319. {
  320. try {
  321. release();
  322. }
  323. catch(...) {}
  324. }
  325. void steal(std::ostream &out)
  326. {
  327. release();
  328. output_stream_ = &out;
  329. output_ = out.rdbuf(this);
  330. }
  331. int release()
  332. {
  333. int r=0;
  334. if(output_stream_) {
  335. if(write()!=0)
  336. r=-1;
  337. output_stream_->rdbuf(output_);
  338. output_=0;
  339. output_stream_=0;
  340. }
  341. return r;
  342. }
  343. protected:
  344. int overflow(int c)
  345. {
  346. if(write()!=0)
  347. return -1;
  348. if(c!=EOF) {
  349. *pptr()=c;
  350. pbump(1);
  351. }
  352. return 0;
  353. }
  354. private:
  355. int write()
  356. {
  357. if(static_cast<Filter*>(this)->convert(pbase(),pptr(),output_)!=0) {
  358. output_stream_->setstate(std::ios_base::failbit);
  359. return -1;
  360. }
  361. setp(buffer_,buffer_ + BufferSize);
  362. return 0;
  363. }
  364. char buffer_[BufferSize];
  365. std::streambuf *output_;
  366. std::ostream *output_stream_;
  367. };
  368. template<typename Filter>
  369. class filterbuf<Filter,0> : public std::streambuf {
  370. public:
  371. filterbuf() : output_(0), output_stream_(0)
  372. {
  373. }
  374. filterbuf(std::ostream &out) : output_(0), output_stream_(0)
  375. {
  376. steal(out);
  377. }
  378. ~filterbuf()
  379. {
  380. release();
  381. }
  382. void steal(std::ostream &out)
  383. {
  384. release();
  385. output_stream_ = &out;
  386. output_ = out.rdbuf(this);
  387. }
  388. int release()
  389. {
  390. int r=0;
  391. if(output_stream_) {
  392. output_stream_->rdbuf(output_);
  393. output_=0;
  394. output_stream_=0;
  395. }
  396. return r;
  397. }
  398. protected:
  399. int overflow(int c)
  400. {
  401. if(c!=EOF) {
  402. char tmp=c;
  403. if(write(&tmp,&tmp+1)!=0)
  404. return -1;
  405. }
  406. return 0;
  407. }
  408. std::streamsize xsputn(char const *s,std::streamsize size)
  409. {
  410. if(write(s,s+size)!=0)
  411. return -1;
  412. return size;
  413. }
  414. private:
  415. int write(char const *begin,char const *end)
  416. {
  417. if(static_cast<Filter*>(this)->convert(begin,end,output_)!=0) {
  418. output_stream_->setstate(std::ios_base::failbit);
  419. return -1;
  420. }
  421. return 0;
  422. }
  423. std::streambuf *output_;
  424. std::ostream *output_stream_;
  425. };
  426. } // util
  427. } // cppcms
  428. #endif