File: dcistrmb.cc

package info (click to toggle)
dcmtk 3.6.0-12
  • links: PTS, VCS
  • area: main
  • in suites: wheezy
  • size: 32,976 kB
  • sloc: cpp: 193,852; ansic: 46,292; sh: 4,020; makefile: 3,969; perl: 3,278; lex: 94
file content (370 lines) | stat: -rw-r--r-- 10,556 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
/*
 *
 *  Copyright (C) 2002-2010, OFFIS e.V.
 *  All rights reserved.  See COPYRIGHT file for details.
 *
 *  This software and supporting documentation were developed by
 *
 *    OFFIS e.V.
 *    R&D Division Health
 *    Escherweg 2
 *    D-26121 Oldenburg, Germany
 *
 *
 *  Module:  dcmdata
 *
 *  Author:  Marco Eichelberg
 *
 *  Purpose: DcmInputBufferStream and related classes,
 *    implements input to blocks of memory as needed in the dcmnet module.
 *
 *  Last Update:      $Author: joergr $
 *  Update Date:      $Date: 2010-10-14 13:14:08 $
 *  CVS/RCS Revision: $Revision: 1.9 $
 *  Status:           $State: Exp $
 *
 *  CVS/RCS Log at end of file
 *
 */

#include "dcmtk/config/osconfig.h"
#include "dcmtk/dcmdata/dcistrmb.h"
#include "dcmtk/dcmdata/dcerror.h"

#define DCMBUFFERPRODUCER_BUFSIZE 1024

DcmBufferProducer::DcmBufferProducer()
: DcmProducer()
, buffer_(NULL)
, backup_(new unsigned char[DCMBUFFERPRODUCER_BUFSIZE])
, bufSize_(0)
, bufIndex_(0)
, backupIndex_(DCMBUFFERPRODUCER_BUFSIZE)
, backupStart_(DCMBUFFERPRODUCER_BUFSIZE)
, status_(EC_Normal)
, eosflag_(OFFalse)
{
  if (!backup_) status_ = EC_MemoryExhausted;
}


DcmBufferProducer::~DcmBufferProducer()
{
  delete[] backup_;
}


OFBool DcmBufferProducer::good() const
{
  return status_.good();
}

OFCondition DcmBufferProducer::status() const
{
  return status_;
}

OFBool DcmBufferProducer::eos() 
{
  // end of stream is true if the user has called setEos() before
  // and there is no more data available in the current buffer.
  // We also flag end of stream if the status is bad.
  return (eosflag_ && (avail() == 0)) || (!status_.good());
}


offile_off_t DcmBufferProducer::avail()
{
  if (status_.good())
  {
    // in the backup buffer, we have (DCMBUFFERPRODUCER_BUFSIZE - backupIndex_)
    // bytes available. In the user buffer, we have (bufSize_ - bufIndex_).
    return DCMBUFFERPRODUCER_BUFSIZE + bufSize_ - bufIndex_ - backupIndex_;
  }
  else return 0;
}


offile_off_t DcmBufferProducer::read(void *buf, offile_off_t buflen)
{
  offile_off_t result = 0;
  if (status_.good() && buflen && buf)
  {
    unsigned char *target = OFstatic_cast(unsigned char *, buf);
    if (backupIndex_ < DCMBUFFERPRODUCER_BUFSIZE)
    {
      // we have data in the backup buffer, read first
      result = DCMBUFFERPRODUCER_BUFSIZE - backupIndex_;
      if (result > buflen) result = buflen;
      memcpy(target, backup_ + backupIndex_, OFstatic_cast(size_t, result));
      backupIndex_ += result;
      target += result;
      buflen -= result;
    }

    if (buflen && bufSize_)
    {
      // read data from user buffer
      offile_off_t numbytes = bufSize_ - bufIndex_;
      if (numbytes > buflen) numbytes = buflen;
      memcpy(target, buffer_ + bufIndex_, OFstatic_cast(size_t, numbytes));
      bufIndex_ += numbytes;
      result += numbytes;
    }
  }
  return result;
}


offile_off_t DcmBufferProducer::skip(offile_off_t skiplen)
{
  offile_off_t result = 0;
  if (status_.good() && skiplen)
  {
    if (backupIndex_ < DCMBUFFERPRODUCER_BUFSIZE)
    {
      // we have data in the backup buffer, skip first
      result = DCMBUFFERPRODUCER_BUFSIZE - backupIndex_;
      if (result > skiplen) result = skiplen;
      backupIndex_ += result;
      skiplen -= result;
    }

    if (skiplen && bufSize_)
    {
      // skip data from user buffer
      offile_off_t skipbytes = bufSize_ - bufIndex_;
      if (skipbytes > skiplen) skipbytes = skiplen;
      bufIndex_ += skipbytes;
      result += skipbytes;
    }
  }
  return result;
}

void DcmBufferProducer::putback(offile_off_t num)
{
  if (status_.good() && num)
  {
    if (bufSize_ && bufIndex_)
    {
      // since bufIndex_ > 0, data has already been read from the user buffer.
      // This means we should putback in the user buffer first, and only
      // if this is not sufficient we also touch the backup buffer.
      if (num > bufIndex_)
      {
        num -= bufIndex_;
        bufIndex_ = 0;
      }
      else
      {
        bufIndex_ -= num;
        num = 0;
      }
    }

    if (num && (backupIndex_ > backupStart_))
    {
      // there is still a number of bytes to putback, and we have data in the
      // backup buffer, so we can actually putback something there.
      // This will cause the next read operation to read from the backup
      // buffer first and only then access the user buffer.
      if (num > (backupIndex_ - backupStart_))
      {
        num -= backupIndex_ - backupStart_;
        backupIndex_ = backupStart_;
      }
      else
      {
        backupIndex_ -= num;
        num = 0;
      }
    }

    if (num)
    {
      // we didn't manage to execute the putback request because there was
      // not enough data available in both buffers. Producer failure.
      status_ = EC_PutbackFailed;
    }
  }
}

void DcmBufferProducer::setBuffer(const void *buf, offile_off_t buflen)
{
  if (status_.good())
  {
    if (buffer_ || eosflag_)
    {
      // error: attempt to set new buffer without calling releaseBuffer before
      // or after calling setEos.
      status_ = EC_IllegalCall;
    }
    else if (buf && buflen)
    {
      buffer_   = OFstatic_cast(unsigned char *, OFconst_cast(void *, buf));
      bufSize_  = buflen;
      bufIndex_ = 0;
    }
  }
}

void DcmBufferProducer::releaseBuffer()
{
  // releaseBuffer() might be called multiple times, so buffer_ could already be NULL.
  if (status_.good() && buffer_)
  {
    // compute the least number of bytes that we have to store in the backup buffer
    offile_off_t numBytes = bufSize_ - bufIndex_;

    if (numBytes > backupIndex_)
    {
      // number of bytes is larger than free space in backup buffer; fail.
      status_ = EC_IllegalCall;
    }
    else
    {
      // if number of bytes is smaller than free space in backup buffer, make as large as possible
      if (numBytes < backupIndex_)
      {
        numBytes = (backupIndex_ < bufSize_) ? backupIndex_ : bufSize_;
      }

      // if number of bytes is smaller than backup buffer, move old
      // data in backup buffer to keep older data available for putback operations
      if (numBytes < DCMBUFFERPRODUCER_BUFSIZE)
      {
        // move (DCMBUFFERPRODUCER_BUFSIZE - numBytes) bytes from end of backup buffer
        // to start of backup buffer. Everything else will be overwritten from the
        // user buffer.
        memmove(backup_, backup_ + numBytes, OFstatic_cast(size_t, DCMBUFFERPRODUCER_BUFSIZE - numBytes));

        // adjust backupStart_
        if (backupStart_ < numBytes) backupStart_ = 0; else backupStart_ -= numBytes;
      }
      else
      {
        // the backup buffer will be filled completely from the user buffer
        backupStart_ = 0;
      }

      // copy (numBytes) bytes from the end of the user buffer to the end of the backup buffer
      memcpy(backup_ + DCMBUFFERPRODUCER_BUFSIZE - numBytes, buffer_ + bufSize_ - numBytes, OFstatic_cast(size_t, numBytes));

      // adjust backupIndex_
      if (backupIndex_ == DCMBUFFERPRODUCER_BUFSIZE)
      {
        // there was no unread data in the backup buffer before.
        // backupIndex_ only depends on the number of unread bytes in the user buffer.
        // we know that (bufSize_ - bufIndex_ < DCMBUFFERPRODUCER_BUFSIZE) because this was tested before.
        backupIndex_ = DCMBUFFERPRODUCER_BUFSIZE + bufIndex_ - bufSize_;
      }
      else
      {
        // there was unread data in the backup buffer before.
        // This implies that all of the user buffer is unread and the complete user
        // buffer fits into the free space in the backup buffer, because otherwise
        // we would not have got this far.
        // Adjust backupIndex_ by the number of bytes we have moved the content of the backup buffer.
        backupIndex_ -= numBytes;
      }

      // release user buffer
      buffer_ = NULL;
      bufSize_ = 0;
      bufIndex_ = 0;
    }
  }

  // the number of bytes that can be putback after this operation depends
  // on the size of the backup buffer and on the number of unread bytes
  // in both buffers at the time of the releaseBuffer() operation.
  // If the user only calls releaseBuffer() when most data has been read
  // from the buffer, we should be able to putback almost 1K.
}

void DcmBufferProducer::setEos()
{
  eosflag_ = OFTrue;
}

/* ======================================================================= */

DcmInputBufferStream::DcmInputBufferStream()
: DcmInputStream(&producer_) // safe because DcmInputStream only stores pointer
, producer_()
{
}

DcmInputBufferStream::~DcmInputBufferStream()
{
#ifdef DEBUG
  if ((!eos()) && (avail() > 0))
  {
      DCMDATA_WARN("closing unflushed DcmInputBufferStream, loss of data!");
  }
#endif
}

DcmInputStreamFactory *DcmInputBufferStream::newFactory() const
{
  // we don't support delayed loading from buffer streams
  return NULL;
}

void DcmInputBufferStream::setBuffer(const void *buf, offile_off_t buflen)
{
  producer_.setBuffer(buf, buflen);

  // if there is a compression filter, the following call will
  // cause it to feed the compression engine with data from the
  // new buffer.
  skip(0);
}

void DcmInputBufferStream::releaseBuffer()
{
  producer_.releaseBuffer();
}

void DcmInputBufferStream::setEos()
{
  producer_.setEos();
}


/*
 * CVS/RCS Log:
 * $Log: dcistrmb.cc,v $
 * Revision 1.9  2010-10-14 13:14:08  joergr
 * Updated copyright header. Added reference to COPYRIGHT file.
 *
 * Revision 1.8  2010-02-22 11:39:54  uli
 * Remove some unneeded includes.
 *
 * Revision 1.7  2009-11-04 09:58:09  uli
 * Switched to logging mechanism provided by the "new" oflog module
 *
 * Revision 1.6  2007-02-19 15:45:31  meichel
 * Class DcmInputStream and related classes are now safe for use with
 *   large files (2 GBytes or more) if supported by compiler and operating system.
 *
 * Revision 1.5  2006/08/15 15:49:54  meichel
 * Updated all code in module dcmdata to correctly compile when
 *   all standard C++ classes remain in namespace std.
 *
 * Revision 1.4  2005/12/08 15:41:13  meichel
 * Changed include path schema for all DCMTK header files
 *
 * Revision 1.3  2004/02/04 16:33:40  joergr
 * Adapted type casts to new-style typecast operators defined in ofcast.h.
 *
 * Revision 1.2  2002/09/19 08:32:29  joergr
 * Added explicit type casts to keep Sun CC 2.0.1 quiet.
 *
 * Revision 1.1  2002/08/27 16:55:48  meichel
 * Initial release of new DICOM I/O stream classes that add support for stream
 *   compression (deflated little endian explicit VR transfer syntax)
 *
 *
 */