(Another) method to extract strings from wxDataInputStream's

If you have a cool piece of software to share, but you are not hosting it officially yet, please dump it in here. If you have code snippets that are useful, please donate!
Post Reply
z64555
In need of some credit
In need of some credit
Posts: 4
Joined: Fri Oct 26, 2012 12:52 am

(Another) method to extract strings from wxDataInputStream's

Post by z64555 »

Just a quick, rather unimaginative function that allows one to extract a string of specified length from a wxDataInputStream:

Code: Select all

wxString wxDataInputStream::ReadString( const wxUint32 len )
{
    wxString ret;

    if ( len > 0 )
    {
#if wxUSE_UNICODE
        wxCharBuffer tmp(len + 1);
        if ( tmp )
        {
            m_input->Read(tmp.data(), len);
            tmp.data()[len] = '\0';
            ret = m_conv->cMB2WX(tmp.data());
        }
#else
        wxStringBuffer buf(ret, len);
        if ( buf )
            m_input->Read(buf, len);
#endif
    }

    return ret;
}
It is a (very minor) modified copy of the existing wxDataInputString::ReadString() method (wxWidgets 2.9.4), but this one takes in a wxUint32 argument for its length instead of trying to read in a int32 automatically. This can be useful when you want to extract multiple strings from a data file that are actually saved as a part of a much larger string, or when the string length is stored as something other than an Uint32 (like a Uint8 or Uint16).



One thing to note, I ended up resorting to making a full copy of "wx/datstrm.h" and "wx/datstrm.cpp" in order to add this method, as MSVC wouldn't allow me to derive from the wxDataInputStream class by simply doing this:

Code: Select all

class DataInputStream : public wxDataInputStream
{
public:
#if wxUSE_UNICODE
    DataInputStream(wxInputStream& s, const wxMBConv& conv = wxConvUTF8 );
#else
    DataInputStream(wxInputStream& s);
#endif
    ~DataInputStream();

    wxString ReadString( wxUint32 len );
}

// Constructors are identical to wxDataInputStream
// wxString ReadString( wxUint32 len) is also identical to snippet above
It gave me an error code complaining about "Could not find adequate default constructor for wxDataInputStream" as well as complain about the initializer list. After about a couple of hours of trying to figure out a way around this, I just gave in and made my own mydatstrm.h and mydatstrm.cpp and used them instead of wxdatstrm.h and wxdatstrm.cpp, respectively. :roll:
z64555
In need of some credit
In need of some credit
Posts: 4
Joined: Fri Oct 26, 2012 12:52 am

Re: (Another) method to extract strings from wxDataInputStre

Post by z64555 »

With the help of this article, I figured out how the iniatialization list really works as well as better understand how classes are constructed.

The net result is a better version of my previous snippet, this time with a lot less copy pasta from wxWidget's source code:

Header file:

Code: Select all

#ifndef _WX_DATSTREAM2_HPP_
#define _WX_DATSTREAM2_HPP_

#include "wx/stream.h"
#include "wx/convauto.h"
#include "wx/datstrm.h"

#if wxUSE_STREAMS

class wxDataInputStream2 : public wxDataInputStream
{
public:
#if wxUSE_UNICODE
	wxDataInputStream2(wxInputStream& s, const wxMBConv& conv = wxConvUTF8 );
#else
	wxDataInputStream2(wxInputStream& s);
#endif


	wxString ReadString( const wxUint32 len );
};

#endif	// wxUseStreams
#endif	// _WX_DATSREAM2_HPP_
Implementation file:

Code: Select all

// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"

#ifdef __BORLANDC__
  #pragma hdrstop
#endif

#if wxUSE_STREAMS

#include "code/datstrm2.hpp"

#ifndef WX_PRECOMP
    #include "wx/math.h"
#endif //WX_PRECOMP

// ---------------------------------------------------------------------------
// wxDataInputStream
// ---------------------------------------------------------------------------

#if wxUSE_UNICODE
wxDataInputStream2::wxDataInputStream2(wxInputStream& s, const wxMBConv& conv)
  : wxDataInputStream( s, conv )
#else
wxDataInputStream2::wxDataInputStream2(wxInputStream& s)
  : wxDataInputStream( s ), m_be_order(false)
#endif
{
}

wxString wxDataInputStream2::ReadString( const wxUint32 len )
{
    wxString ret;

    if ( len > 0 )
    {
#if wxUSE_UNICODE
        wxCharBuffer tmp(len + 1);
        if ( tmp )
        {
            m_input->Read(tmp.data(), len);
            tmp.data()[len] = '\0';
            ret = m_conv->cMB2WX(tmp.data());
        }
#else
        wxStringBuffer buf(ret, len);
        if ( buf )
            m_input->Read(buf, len);
#endif
    }

    return ret;
}

#endif  // wxUSE_STREAMS
The main difference is the usage of an initialization list in the wxDataInputStream2 class constructor to pass arguments to the parent class's constructor (wxDataInputStream). Previous attempts to do something like this did not end well, because the compiler could not find a default constructor for the wxDataInputStream class (because there wasn't one) and I did not know how/where to specify which constructor to use.
Post Reply