Hi,

I am using wt in an embedded application and therefore I have limited memory. I 
need to provide download of files and for that I use a WFileResource. >From 
looking at the implementation of WFileResource, it seems that the entire file 
needs to fit in memory. The file is read until no more data is returned from 
the file stream before the streamResourceData method returns.

The documentation for streamResourceData says, that the method should return 
false if not all data has been streamed. I have modified WFileResouce to behave 
this way and to know if a file has been partly streamed (see code below). But 
when I use this modified version, the file download stalls and if I quit the 
web application, I can see that only the first chunk of the file has been sent. 
I have been debugging the app, an I can see that the streamResourceData method 
is only invoked once and not multiple times as I would expect.

Can anyone here help me? Am I doing something wrong or is this a bug in the 
framework?

The modified code follows..
---------------
WFileResource :

// This may look like C code, but it's really -*- C++ -*-
/*
 * Copyright (C) 2008 Emweb bvba, Kessel-Lo, Belgium.
 *
 * See the LICENSE file for terms of use.
 */
#ifndef WFILE_RESOURCE_H_
#define WFILE_RESOURCE_H_

#include <string>
#include <fstream>
#include <Wt/WResource>

namespace Wt {

/*! \class WFileResource Wt/WFileResource Wt/WFileResource
 *  \brief A Resource which streams data from a local file
 *
 * To update the resource, either use setFileName() to point it to a new file,
 * or emit dataChanged() if only the file contents has changed, but not
 * the filename.
 */
class WT_API WFileResource : public WResource
{
public:
  /*! \brief Create a new resource with given mime-type and contents stored
   *         in filename.
   */
  WFileResource(const std::string& mimeType, const std::string& fileName);

  /*! \brief Destroy the resource.
   *
   * It is up to the user to make sure that the resource is nog longer
   * in use (by e.g. a WImage).
   */
  ~WFileResource();

  /*! \brief Set a (different) filename.
   *
   * Set the location of the file on the local filesystem which must be
   * streamed for this resource.
   */
  void setFileName(const std::string& fileName);

  /*! \brief Get the filename.
   */
  const std::string& fileName() const { return fileName_; }

  /*! \brief Get the mime-type.
   */
  const std::string& mimeType() const { return mimeType_; }

  /*! \brief Set the mime-type.
   */
  void setMimeType(const std::string& mimeType);

private:
  std::string mimeType_;
  std::string fileName_;
  std::ifstream* fileStream;
  bool fileIsOpen;

  /*! \brief Block size for data to be put in the output stream for
   * streamResourceData.
   */
  static const int BLOCK_SIZE = 1024;

protected:

  /*! \brief Return the mimetype
   */
  virtual const std::string resourceMimeType() const;

  /*! \brief Stream the data for this resource.
   */
  virtual bool streamResourceData(std::ostream& stream,
                                  const ArgumentMap& arguments);
};

}

#endif // WFILE_RESOURCE_H_

-------------------------------
WFileResource.C :

/*
 * Copyright (C) 2008 Emweb bvba, Kessel-Lo, Belgium.
 *
 * See the LICENSE file for terms of use.
 */

#include <fstream>

#include "Wt/WFileResource"

namespace Wt {

WFileResource::WFileResource(const std::string& mimeType,
                             const std::string& fileName)
  : WResource(),
    mimeType_(mimeType),
    fileName_(fileName),
    fileStream(NULL),
    fileIsOpen(false)
{
  setReentrant(true);
}

WFileResource::~WFileResource()
{
  if (fileStream != NULL)
  {
    delete fileStream;
  }
}

void WFileResource::setFileName(const std::string& fileName)
{
  fileName_ = fileName;
  dataChanged.emit();
}

void WFileResource::setMimeType(const std::string& mimeType)
{
  mimeType_ = mimeType;
  dataChanged.emit();
}

const std::string WFileResource::resourceMimeType() const
{
  return mimeType_;
}

bool WFileResource::streamResourceData(std::ostream& stream,
                                       const ArgumentMap& arguments)
{
  if (!fileIsOpen)
  {
    fileIsOpen = true;
    fileStream = new std::ifstream(fileName_.c_str(), std::ios::in | 
std::ios::binary);
  }

  int count = 0;

  char c;
  while (fileStream->good()
         && count < BLOCK_SIZE)
  {
    fileStream->get(c);
    stream.put(c);
    count++;
  }

  if (fileStream->good())
  {
    // we have more data
    return false;
  }
  else
  {
     delete fileStream;
     fileIsOpen = false;
     return true;
  }
}

}


-- 
Med venlig hilsen / Best regards

Michael Sørensen Loft
Senior Software Developer
Tlf. 41 95 36 58 - [EMAIL PROTECTED]

--------------------------------------------------
Mjølner Informatics A/S
Finlandsgade 10, 8200 Århus N
Tlf. 70 27 43 43 - www.mjolner.dk
--------------------------------------------------

Denne e-mail kan indeholde fortrolig information, som ikke må kopieres eller
udleveres til anden side, og som kun er bestemt for den angivne modtager.
Hvis du ved en fejltagelse har modtaget denne e-mail, skal du venligst
orientere afsenderen herom og straks slette e-mailen.

-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/
_______________________________________________
witty-interest mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/witty-interest

Reply via email to