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
////////////////////////////////////////////////////////////////////////////////
/// Name:         Ed2kHash Class
///
/// Purpose:      aMule ed2k link creator
///
/// Author:       ThePolish <thepolish@vipmail.ru>
///
/// Copyright (c) 2004-2011 ThePolish ( thepolish@vipmail.ru )
///
/// Copyright (c) 2004-2011 Marcelo Roberto Jimenez ( phoenix@amule.org )
///
/// This program is free software; you can redistribute it and/or modify
/// it under the terms of the GNU General Public License as published by
/// the Free Software Foundation; either version 2 of the License, or
/// (at your option) any later version.
///
/// This program is distributed in the hope that it will be useful,
/// but WITHOUT ANY WARRANTY; without even the implied warranty of
/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
/// GNU General Public License for more details.
///
/// You should have received a copy of the GNU General Public License
/// along with this program; if not, write to the
/// Free Software Foundation, Inc.,
/// 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA
////////////////////////////////////////////////////////////////////////////////


#include <wx/ffile.h>
#include <wx/log.h>
#include <wx/regex.h>

#include "ed2khash.h"


/// Constructor
Ed2kHash::Ed2kHash():MD4()
{
  m_ed2kArrayOfHashes.Clear();
  m_filename.Clear();
  m_fileSize=0;
}

/// Destructor
Ed2kHash::~Ed2kHash()
{}

/// Set Ed2k hash from a file
// returns false if aborted
bool Ed2kHash::SetED2KHashFromFile(const wxFileName& filename, MD4Hook hook)
{
  // Open file and let wxFFile destructor close the file
  // Closing it explicitly may crash on Win32 ...
  wxFFile file(filename.GetFullPath(), wxT("rbS"));
  if (! file.IsOpened())
    {
	  // This doesn't make much sense to me, but it is what it was before and actually works.
	  wxLogError(_("Unable to open %s"), ((const char*)filename.GetFullPath().mb_str(wxConvISO8859_1)));
      return (false);
    }
  else
    {
      unsigned char ret[MD4_HASHLEN_BYTE];
      MD4Context hdc;

      size_t read;
      size_t partcount;
      wxFileOffset totalread;

      char *buf = new char[BUFSIZE];

      bool goAhead = true;

#ifdef WANT_STRING_IMPLEMENTATION

      wxString tmpHash(wxEmptyString);
#else

      unsigned char* tmpCharHash = NULL;
#endif
      // Clear Ed2k Hash
      m_ed2kArrayOfHashes.Clear();

      // Processing each block
      totalread=0;
      partcount = 0;
      while (!file.Eof())
        {
          size_t dataread = 0;
          MD4Init(&hdc);
          while (dataread < PARTSIZE && !file.Eof())
            {
              if (hook)
                {
                  goAhead = hook((int)((double)(100.0 * totalread) / file.Length()));
                }
              if (goAhead)
                {
                  if ((dataread + BUFSIZE) > PARTSIZE)
                    {
                      read = file.Read(buf, PARTSIZE - dataread);
                    }
                  else
                    {
                      read = file.Read(buf, BUFSIZE);
                    }
                  dataread += read;
                  totalread += read;
                  MD4Update(&hdc, reinterpret_cast<unsigned char const *>(buf),
                            read);
                }
              else
                {
		  delete [] buf;
                  return (false);
                }

            }
          MD4Final(&hdc, ret);

          // Add part-hash
          m_ed2kArrayOfHashes.Add(charToHex(reinterpret_cast<const char *>(ret),
                                            MD4_HASHLEN_BYTE));

          partcount++;

#ifdef WANT_STRING_IMPLEMENTATION
          // MD4_HASHLEN_BYTE is ABSOLUTELY needed as we dont want NULL
          // character to be interpreted as the end of the parthash string
#if wxUSE_UNICODE

          tmpHash += wxString(reinterpret_cast<const wchar_t *>(ret),MD4_HASHLEN_BYTE);
#else

          tmpHash += wxString(reinterpret_cast<const char *>(ret),MD4_HASHLEN_BYTE);
#endif
#else

          unsigned char *tmpPtr = (unsigned char*)realloc(tmpCharHash,
                                                sizeof(unsigned char) * (MD4_HASHLEN_BYTE * partcount));
	  if (tmpPtr) {
		  tmpCharHash = tmpPtr;
	  } else {
		  delete [] buf;
		  free(tmpCharHash);
		  wxLogError(_("Out of memory while calculating ed2k hash!"));
		  return (false);
	  }
          memcpy ( tmpCharHash + MD4_HASHLEN_BYTE * (partcount - 1), ret, MD4_HASHLEN_BYTE );
#endif

        }

      delete [] buf;

      // hash == hash of concatenned parthashes
      if (partcount > 1)
        {
          wxString finalHash;

#ifdef WANT_STRING_IMPLEMENTATION

          finalHash=calcMd4FromString(tmpHash);
#else

          MD4Init(&hdc);
          MD4Update(&hdc, tmpCharHash, MD4_HASHLEN_BYTE * partcount);
          MD4Final(&hdc, ret);

          finalHash = charToHex(reinterpret_cast<const char *>(ret),
                                MD4_HASHLEN_BYTE);
#endif

          m_ed2kArrayOfHashes.Add(finalHash);
        }

#ifndef WANT_STRING_IMPLEMENTATION
      free(tmpCharHash);
      tmpCharHash=NULL;
#endif

      m_ed2kArrayOfHashes.Shrink();

      // Set members
      m_fileSize = file.Length();
      m_filename = filename.GetFullName();

      return true;
    }
}

/// Set Ed2k hash from a file
bool Ed2kHash::SetED2KHashFromFile(const wxString& filename, MD4Hook hook)
{
  return SetED2KHashFromFile(wxFileName(filename), hook);
}

#define WXLONGLONGFMTSPEC wxT(wxLongLongFmtSpec)

/// Get Ed2k link
wxString Ed2kHash::GetED2KLink(const bool addPartHashes, const wxArrayString* arrayOfUrls)
{
  // Constructing ed2k basic link
  wxString ed2kLink = wxT("ed2k://|file|") + CleanFilename(m_filename)
                      + wxString::Format(wxT("|%") WXLONGLONGFMTSPEC wxT("u|"), m_fileSize)<--- There is an unknown macro here somewhere. Configuration is required. If wxT is a macro then please configure it.
                      + m_ed2kArrayOfHashes.Last() + wxT("|");


  // Add optional URLs
  if ( arrayOfUrls && !arrayOfUrls->IsEmpty())
    {
      size_t i;
      for ( i = 0; i < arrayOfUrls->GetCount(); i++ )
        {
          ed2kLink += wxT("s=") + (*arrayOfUrls)[i] + wxT("|");
        }
    }

  // Add Optional part-hashes
  if (addPartHashes && m_ed2kArrayOfHashes.GetCount()>1)
    {
      ed2kLink += wxT("p=");
      size_t i;
      for (i=0;i<(m_ed2kArrayOfHashes.GetCount()-1);++i)
        {
          ed2kLink += m_ed2kArrayOfHashes[i] + wxT(":");
        }
      ed2kLink.RemoveLast(); // Remove last :
      ed2kLink += wxT("|");
    }

  // Add last slash
  ed2kLink += wxT("/");

  return ed2kLink;
}

/// Strip all non-alphanumeric characters of a filename string
wxString Ed2kHash::CleanFilename(const wxString& filename)
{
  wxString name(filename);

  wxRegEx toStrip(wxT("[^[:alnum:]_.-]"));
  toStrip.Replace(&name, wxT("_"));

  return (name);
}

/// Get Ed2k Array of hashes
wxArrayString Ed2kHash::GetED2KHash()
{
  return (m_ed2kArrayOfHashes);
}
// File_checked_for_headers