Linux programming implementation of file production ed2k chain

  • 2020-04-02 03:01:07
  • OfStack

This program depends on c99, only support terminal "standard input", the link into the "standard output" and output, error to "mark error output" and output.

The md4 encoding code comes from the network.

Compile command: gcc-std = c99-o ed2k md4.c   Ed2k. C   Utils. C
User command: ed2k < The File... >
The resulting chain is the shortest form: ed2k://|file| < FileName > | < FileSize > | < FileHash > |/

C + + version:

Compile command: g++ -o ed2k ed2k.cpp utils.cpp md4hash.cpp ed2khash.cpp
User command: ed2k < The File... >     (although --help can see the other options, none are implemented)

Defs. H


#ifndef MYCODE_DEFS_H
#define MYCODE_DEFS_H
 
#include <stdint.h>  
#include <stddef.h> 
#include <stdbool.h>
#endif
 
#if __cplusplus
# define BEGIN_NAMESPACE_MYCODE namespace mc {
# define END_NAMESPACE_MYCODE }
# if __cplusplus < 201103L
# define nullptr ((void*)0)
# endif
#endif 
 
#endif 

Utils. H


#ifndef MYCODE_UTILS_H
#define MYCODE_UTILS_H
 
#include <stdio.h>
#if __cplusplus
# include <utility>
# include <string>
# include <fstream>
#endif 
#include "defs.h"
 
#if __cplusplus
extern "C" {
#endif
 
#undef byteswap32
#define byteswap32(x) 
  ( (((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | 
   (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24) )
 
#undef htobe32
#undef htole32
#if __BYTE_ORDER == __LITTLE_ENDIAN
# define htobe32(x) byteswap32(x)
# define htole32(x) (x)
#else
# define htobe32(x) (x)
# define htole32(x) byteswap32(x)
#endif
 
enum { string_npos = (size_t)-1 };

size_t string_find(const char *str, size_t size, char c);

size_t string_rfind(const char *str, size_t size, char c);
 
void setBigEndian_uint32(uint32_t *data, size_t n);
 
char* toHexString_uint32(char *buf, size_t bufSize,
             const uint32_t *data, size_t n);
 
char* createShortFileName(char *buf, size_t bufSize,
             const char *fullName, size_t size);

const char* getShortFileName(const char* fullName, size_t size);
 

size_t getFileSize(FILE *in, int *state);
 
#if __cplusplus
} 
#endif
 

#if __cplusplus
BEGIN_NAMESPACE_MYCODE
 
# if __cplusplus >= 201103L
# define mc_move(x) std::move(x)
# else
# define mc_move(x) (x);
# endif
 
///////////////////////////////////////////////////////////////////////////////
 
template<class T>
void setBigEndian(T*, size_t);
 
template<>
inline void setBigEndian<uint32_t>(uint32_t *p, size_t n)
{ setBigEndian_uint32(p, n); }
 
///////////////////////////////////////////////////////////////////////////////
 
template<class T>
std::string toHexString(T*, size_t);
 
template<>
inline std::string toHexString<uint32_t>(uint32_t *p, size_t n)
{
  std::string strHex;
  char buf[9];
  for (size_t i = 0; i < n; ++i) {
    sprintf(buf, "%08X", p[i]);
    strHex += buf;
  }
  return mc_move(strHex);
}
 
///////////////////////////////////////////////////////////////////////////////
 
std::string getShortFileName(const std::string& fullName);
 
void getShortFileName(std::string *shortName, const std::string& fullName);
 
size_t getFileSize(std::ifstream& f);
 
END_NAMESPACE_MYCODE
#endif 
 
#endif 

Utils. C


#include "utils.cpp"

Utils. CPP


#include <string.h>
#include "utils.h"
 
#if __cplusplus
extern "C" {
#endif
 
void setBigEndian_uint32(uint32_t *data, size_t n)
{
  for (size_t i = 0; i < n; ++i)
    data[i] = htobe32(data[i]);
}
 
char* toHexString_uint32(char *buf, size_t bufSize, const uint32_t *data, size_t n)
{
  char *p = buf;
  size_t i = 0;
  size_t one_uint32_size = sizeof(uint32_t);
   
  if ( one_uint32_size * n < bufSize )
  {
    while (i < n) {
      sprintf(p, "%08X", data[i++]);
      p += 8;
    }
  }
   
  *p = '0';
  return buf;
}
 
size_t string_find(const char *str, size_t size, char c)
{
  size_t pos = 0;
  while (pos < size) {
    if (str[pos] == c)
      return pos;
    ++pos;
  }
  return string_npos;
}
 
size_t string_rfind(const char *str, size_t size, char c)
{
  while (size) {
    if (str[--size] == c)
      return size;
  }
  return string_npos;
}
 
char* createShortFileName(char *buf, size_t bufSize,
                          const char *fullName, size_t size)
{
  const char * p = getShortFileName(fullName, size);
  buf[0] = '0';
  if (p)
  {
    size_t len = strlen(p);
    if (bufSize > len)
      memcpy(buf, p, len + 1);
  }
  return buf;
}
 
const char* getShortFileName(const char *fileName, size_t size)
{
#if _WIN32
  char c = '\';
#else
  char c = '/';
#endif
  size_t pos = string_rfind(fileName, size, c);
  if (pos == string_npos)
    return NULL;
  else
    return fileName + (pos + 1);
}
 
size_t getFileSize(FILE *in, int *state)
{
  *state = 0;
  if (!in)
    return 0;
   
  size_t curpos = ftell(in);
  if (fseek(in, 0, SEEK_END) == -1)
    return 0;
  size_t fileSize = ftell(in);
  if (fseek(in, curpos, SEEK_SET) == -1)
    return 0;
 
  *state = 1;
  return fileSize;
}
 
#if __cplusplus
} 
#endif
 

#if __cplusplus
BEGIN_NAMESPACE_MYCODE
 
void getShortFileName(std::string *shortName, const std::string& fullName)
{
# if _WIN32
  char c = '\';
# else
  char c = '/';
# endif
  size_t pos = fullName.rfind(c);
  if (pos == std::string::npos)
    shortName->assign(fullName);
  else
    shortName->assign(fullName.begin() + pos + 1, fullName.end());
}
 
std::string getShortFileName(const std::string& fullName)
{
  std::string shortName;
  getShortFileName(&shortName, fullName);
  return mc_move(shortName);
}
 
size_t getFileSize(std::ifstream& f)
{
  f.seekg(0, f.end);
  size_t fileSize = f.tellg();
  f.seekg(0);
  return fileSize;
}
 
END_NAMESPACE_MYCODE
#endif 

Md4. H


#ifndef MYCODE_MD4_H
#define MYCODE_MD4_H
 
#include "defs.h"
 
#if __cplusplus
extern "C" {
#endif
   
enum { MD4_COUNT_SIZE = 8, MD4_STATE_SIZE = 16, MD4_BUFFER_SIZE = 64 };
   
typedef struct {
  uint32_t count[2];
  uint32_t state[4];
  uint8_t buffer[MD4_BUFFER_SIZE];
} md4_t;
 
#define md4_data(md4_ptr) ((char*)((md4_ptr)->state))
#define md4_cdata(md4_ptr) ((const char*)((md4_ptr)->state))
#define md4_dataSize() (MD4_STATE_SIZE)
 
void md4_reset(md4_t *md4);
void md4_update(md4_t *md4, const char *src, size_t srcSize);
void md4_finish(md4_t *md4);
void md4_setBigEndian(md4_t *md4);
char* md4_toHashString(char dest[33], const md4_t *md4);
 
#if __cplusplus
}
#endif
 
#endif 

Md4. C



#include <stdio.h>
#include <string.h>
#include "utils.h"
#include "md4.h"
 
#if __cplusplus
extern "C" {
#endif
   
#if __BYTE_ORDER == __LITTLE_ENDIAN
# define md4_htole32_4(buf) 
# define md4_htole32_14(buf) 
# define md4_htole32_16(buf) 
#else
# define md4_htole32_4(buf) 
 (buf)[ 0] = htole32((buf)[ 0]); 
 (buf)[ 1] = htole32((buf)[ 1]); 
 (buf)[ 2] = htole32((buf)[ 2]); 
 (buf)[ 3] = htole32((buf)[ 3])
  
# define md4_htole32_14(buf) 
 (buf)[ 0] = htole32((buf)[ 0]); 
 (buf)[ 1] = htole32((buf)[ 1]); 
 (buf)[ 2] = htole32((buf)[ 2]); 
 (buf)[ 3] = htole32((buf)[ 3]); 
 (buf)[ 4] = htole32((buf)[ 4]); 
 (buf)[ 5] = htole32((buf)[ 5]); 
 (buf)[ 6] = htole32((buf)[ 6]); 
 (buf)[ 7] = htole32((buf)[ 7]); 
 (buf)[ 8] = htole32((buf)[ 8]); 
 (buf)[ 9] = htole32((buf)[ 9]); 
 (buf)[10] = htole32((buf)[10]); 
 (buf)[11] = htole32((buf)[11]); 
 (buf)[12] = htole32((buf)[12]); 
 (buf)[13] = htole32((buf)[13])
  
# define md4_htole32_16(buf) 
 (buf)[ 0] = htole32((buf)[ 0]); 
 (buf)[ 1] = htole32((buf)[ 1]); 
 (buf)[ 2] = htole32((buf)[ 2]); 
 (buf)[ 3] = htole32((buf)[ 3]); 
 (buf)[ 4] = htole32((buf)[ 4]); 
 (buf)[ 5] = htole32((buf)[ 5]); 
 (buf)[ 6] = htole32((buf)[ 6]); 
 (buf)[ 7] = htole32((buf)[ 7]); 
 (buf)[ 8] = htole32((buf)[ 8]); 
 (buf)[ 9] = htole32((buf)[ 9]); 
 (buf)[10] = htole32((buf)[10]); 
 (buf)[11] = htole32((buf)[11]); 
 (buf)[12] = htole32((buf)[12]); 
 (buf)[13] = htole32((buf)[13]); 
 (buf)[14] = htole32((buf)[14]); 
 (buf)[15] = htole32((buf)[15])
 
#endif
 

#define F1(x, y, z) (z ^ (x & (y ^ z)))
#define F2(x, y, z) ((x & y) | (x & z) | (y & z))
#define F3(x, y, z) (x ^ y ^ z)
 

#define MD4STEP(f, w, x, y, z, data, s) 
 ( w += f(x, y, z) + data, w = w<<s | w>>(32-s) )
 
static void md4_transform(uint32_t *state, const uint8_t *buffer)
{
 uint32_t a, b, c, d;
 const uint32_t *src = (const uint32_t *)buffer;
 
 a = state[0];
 b = state[1];
 c = state[2];
 d = state[3];
  
 MD4STEP(F1, a, b, c, d, src[ 0], 3);
 MD4STEP(F1, d, a, b, c, src[ 1], 7);
 MD4STEP(F1, c, d, a, b, src[ 2], 11);
 MD4STEP(F1, b, c, d, a, src[ 3], 19);
 MD4STEP(F1, a, b, c, d, src[ 4], 3);
 MD4STEP(F1, d, a, b, c, src[ 5], 7);
 MD4STEP(F1, c, d, a, b, src[ 6], 11);
 MD4STEP(F1, b, c, d, a, src[ 7], 19);
 MD4STEP(F1, a, b, c, d, src[ 8], 3);
 MD4STEP(F1, d, a, b, c, src[ 9], 7);
 MD4STEP(F1, c, d, a, b, src[10], 11);
 MD4STEP(F1, b, c, d, a, src[11], 19);
 MD4STEP(F1, a, b, c, d, src[12], 3);
 MD4STEP(F1, d, a, b, c, src[13], 7);
 MD4STEP(F1, c, d, a, b, src[14], 11);
 MD4STEP(F1, b, c, d, a, src[15], 19);
 
 MD4STEP(F2, a, b, c, d, src[ 0] + 0x5a827999, 3);
 MD4STEP(F2, d, a, b, c, src[ 4] + 0x5a827999, 5);
 MD4STEP(F2, c, d, a, b, src[ 8] + 0x5a827999, 9);
 MD4STEP(F2, b, c, d, a, src[12] + 0x5a827999, 13);
 MD4STEP(F2, a, b, c, d, src[ 1] + 0x5a827999, 3);
 MD4STEP(F2, d, a, b, c, src[ 5] + 0x5a827999, 5);
 MD4STEP(F2, c, d, a, b, src[ 9] + 0x5a827999, 9);
 MD4STEP(F2, b, c, d, a, src[13] + 0x5a827999, 13);
 MD4STEP(F2, a, b, c, d, src[ 2] + 0x5a827999, 3);
 MD4STEP(F2, d, a, b, c, src[ 6] + 0x5a827999, 5);
 MD4STEP(F2, c, d, a, b, src[10] + 0x5a827999, 9);
 MD4STEP(F2, b, c, d, a, src[14] + 0x5a827999, 13);
 MD4STEP(F2, a, b, c, d, src[ 3] + 0x5a827999, 3);
 MD4STEP(F2, d, a, b, c, src[ 7] + 0x5a827999, 5);
 MD4STEP(F2, c, d, a, b, src[11] + 0x5a827999, 9);
 MD4STEP(F2, b, c, d, a, src[15] + 0x5a827999, 13);
 
 MD4STEP(F3, a, b, c, d, src[ 0] + 0x6ed9eba1, 3);
 MD4STEP(F3, d, a, b, c, src[ 8] + 0x6ed9eba1, 9);
 MD4STEP(F3, c, d, a, b, src[ 4] + 0x6ed9eba1, 11);
 MD4STEP(F3, b, c, d, a, src[12] + 0x6ed9eba1, 15);
 MD4STEP(F3, a, b, c, d, src[ 2] + 0x6ed9eba1, 3);
 MD4STEP(F3, d, a, b, c, src[10] + 0x6ed9eba1, 9);
 MD4STEP(F3, c, d, a, b, src[ 6] + 0x6ed9eba1, 11);
 MD4STEP(F3, b, c, d, a, src[14] + 0x6ed9eba1, 15);
 MD4STEP(F3, a, b, c, d, src[ 1] + 0x6ed9eba1, 3);
 MD4STEP(F3, d, a, b, c, src[ 9] + 0x6ed9eba1, 9);
 MD4STEP(F3, c, d, a, b, src[ 5] + 0x6ed9eba1, 11);
 MD4STEP(F3, b, c, d, a, src[13] + 0x6ed9eba1, 15);
 MD4STEP(F3, a, b, c, d, src[ 3] + 0x6ed9eba1, 3);
 MD4STEP(F3, d, a, b, c, src[11] + 0x6ed9eba1, 9);
 MD4STEP(F3, c, d, a, b, src[ 7] + 0x6ed9eba1, 11);
 MD4STEP(F3, b, c, d, a, src[15] + 0x6ed9eba1, 15);
 
 state[0] += a;
 state[1] += b;
 state[2] += c;
 state[3] += d;
} 
 
 
void md4_reset(md4_t *md4)
{
 md4->count[0] = 0;
 md4->count[1] = 0;
 md4->state[0] = 0x67452301; 
 md4->state[1] = 0xEFCDAB89; 
 md4->state[2] = 0x98BADCFE; 
 md4->state[3] = 0x10325476;
}
 
void md4_update(md4_t *md4, const char *src, size_t srcSize)
{
 uint32_t count = (uint32_t)((md4->count[0] >> 3) & 0x3f);
 
 if ((md4->count[0] += (srcSize << 3)) < (srcSize << 3))
  ++(md4->count[1]);
 md4->count[1] += (srcSize >> 29);
 
 if (count > 0)
 { 
  size_t partSize = MD4_BUFFER_SIZE - count;
  if (srcSize < partSize)
  {
   memcpy(md4->buffer + count, src, srcSize);
   return;
  }
  memcpy(md4->buffer + count, src, partSize);
   
  md4_htole32_16((uint32_t*)md4->buffer);
  md4_transform(md4->state, md4->buffer);
  src += partSize;
  srcSize -= partSize;
 }
 
 while (srcSize >= MD4_BUFFER_SIZE)
 {
  memcpy(md4->buffer, src, MD4_BUFFER_SIZE);
  md4_transform(md4->state, md4->buffer);
  md4_htole32_16((uint32_t *)md4->buffer);
  src += MD4_BUFFER_SIZE;
  srcSize -= MD4_BUFFER_SIZE;
 }
 memcpy(md4->buffer, src, srcSize);
}
 
void md4_finish(md4_t *md4)
{
 uint32_t count = (uint32_t)((md4->count[0] >> 3) & 0x3f);
  
 uint8_t *p = md4->buffer + count;
 *p++ = 0x80;
 
 count = MD4_BUFFER_SIZE - 1 - count;
 
 if (count < 8)
 {
  memset(p, 0, count);
  md4_htole32_16((uint32_t *)md4->buffer);
  md4_transform(md4->state, md4->buffer);
  memset(md4->buffer, 0, 56);
 }
 else
 {
  memset(p, 0, count - 8);
 }
 md4_htole32_14((uint32_t *)md4->buffer);
 
 
 ((uint32_t *)md4->buffer)[14] = md4->count[0];
 ((uint32_t *)md4->buffer)[15] = md4->count[1];
 
 md4_transform(md4->state, md4->buffer);
 md4_htole32_4(md4->state);
  
 memset(md4->buffer, 0, MD4_BUFFER_SIZE);
}
 
void md4_setBigEndian(md4_t *md4)
{
  uint32_t *p = md4->state;
  p[0] = htobe32(p[0]);
  p[1] = htobe32(p[1]);
  p[2] = htobe32(p[2]);
  p[3] = htobe32(p[3]);
}
 
char* md4_toHashString(char dest[33], const md4_t *md4)
{
  return toHexString_uint32(dest, 33, md4->state, 4);
}
 
#if __cplusplus
}
#endif

Ed2k. C


#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "defs.h"
#include "utils.h"
#include "md4.h"
 
enum { CHUNK_SIZE = 9728000, BUFFER_MAX_SIZE = 256 };
 
bool printEd2kLink(const char *fileName)
{
 FILE *in = fopen(fileName, "rb");
 if (!in)
 {
    fprintf(stderr, "error: Open file failed.n");
  return false;
 }
 
  size_t fileSize;
  {
    int state;
    if ((fileSize = getFileSize(in, &state)) == 0)
    {
      if (state == 0)
        fprintf(stderr, "error: get fileSize of '%s' failedn", fileName);
      else
        fprintf(stderr, "error: '%s' is empty.n", fileName);
      fclose(in);
      return false;
    }
  }
 
  const char *shortFileName = getShortFileName(fileName, strlen(fileName));
 if (shortFileName == NULL)
  {
    fprintf(stderr, "error: createNewFilename().n");
    fclose(in);
    return false;
  }
  
 static md4_t md4HashSet, md4FileHash;
  md4_reset(&md4FileHash);
 static char chunk[CHUNK_SIZE];
 size_t readCount;
   
  bool bContinue = true;
  int chunkCount = 0;
 while (bContinue)
 {
  readCount = fread(chunk, sizeof(chunk[0]), CHUNK_SIZE, in);
     
    if (readCount < CHUNK_SIZE)
    {
      if (feof(in)) {
        if (0 == readCount)
          break;
        bContinue = false;
        
      } else {
        fprintf(stderr, "error: Read file failed.n");
        fclose(in);
        return false;
      }
    }
 
  md4_reset(&md4HashSet);
  md4_update(&md4HashSet, chunk, readCount);
  md4_finish(&md4HashSet);
  md4_update(&md4FileHash, md4_data(&md4HashSet), md4_dataSize());
    chunkCount++;
 }
 
 static char strHash[33];
  if (chunkCount > 1) {
    md4_finish(&md4FileHash);
    md4_setBigEndian(&md4FileHash);
    md4_toHashString(strHash, &md4FileHash);
  } else {
    md4_setBigEndian(&md4HashSet);
    md4_toHashString(strHash, &md4HashSet);
  }
   
  fprintf(stdout, "ed2k://|file|%s|%ld|%s|/n", shortFileName, fileSize, strHash);
  md4_reset(&md4FileHash);
 
  fclose(in);
  return true;
}
 
int main(int argc, const char *argv[])
{
 if (argc < 2)
 {
  fprintf(stderr, "error: argc < 2n");
  exit(EXIT_FAILURE);
 }
  
 int linkCount = 0;
 for (int i = 1; i < argc; ++i)
 {
  if (!printEd2kLink(argv[i]))
    {
      fprintf(stderr, "Created %d links.n",linkCount);
        exit(EXIT_FAILURE);
  }
  linkCount++;
 }
  
 exit(EXIT_SUCCESS);
}

MD4Hash. H


#ifndef MYCODE_MD4HASH_H
#define MYCODE_MD4HASH_H
 
#include <string>
#include <utility>
#include "md4.h"
#include "defs.h"
 
BEGIN_NAMESPACE_MYCODE
 
class MD4Hash
{
 friend class MD4HashAlgo;
  struct Data{ uint32_t d[4]; };
 
public:
  MD4Hash();
  MD4Hash(const MD4Hash& o);
#if __cplusplus >= 201103L
  MD4Hash(MD4Hash&& o);
  MD4Hash& operator=(MD4Hash&& o);
#endif
  ~MD4Hash();
  MD4Hash& operator=(const MD4Hash& o);
   
  void setBigEndian();
  std::string toString();
  void swap(MD4Hash& o) { std::swap(m_data, o.m_data); }
   
private:
  Data m_data;
  MD4Hash(uint32_t *data);
};
 
class MD4HashAlgo
{
  md4_t m_md4;
 
public:
  MD4HashAlgo();
  MD4HashAlgo(const MD4HashAlgo& o);
#if __cplusplus >= 201103L
  MD4HashAlgo(MD4HashAlgo&& o);
  MD4HashAlgo& operator=(MD4HashAlgo&& o);
#endif
  ~MD4HashAlgo();
  MD4HashAlgo& operator=(const MD4HashAlgo& o);
   
  void reset() { md4_reset(&m_md4); }
  void update(const char *data, size_t size) { md4_update(&m_md4, data, size); }
  void update(const MD4Hash& hash) { md4_update(&m_md4, (const char*)(hash.m_data.d), 16); }
  void finish() { md4_finish(&m_md4); }
  MD4Hash getHash() { return MD4Hash(m_md4.state); }
  size_t hashSize() { return md4_dataSize(); }
  void swap(MD4HashAlgo& o) { std::swap(m_md4, o.m_md4); }
};
 
END_NAMESPACE_MYCODE
#endif 

ED2KHash. H


#ifndef MYCODE_ED2KHASH_H
#define MYCODE_ED2KHASH_H
 
#include <string>
#include <iostream>
#include "defs.h"
 
BEGIN_NAMESPACE_MYCODE
 
class ED2KHash
{
public:
  enum mode {
    FileHash = 0x01,
    PartHash = 0x10,
   RootHash = 0x20,
    Default = FileHash
  };
   
  ED2KHash(int mode = ED2KHash::Default);
  ED2KHash(const ED2KHash& o);
  ~ED2KHash();
  ED2KHash& operator=(const ED2KHash& o);
#if __cplusplus >= 201103L
  ED2KHash(ED2KHash&& o);
  ED2KHash& operator=(ED2KHash&& o);
#endif
  void exec(const char* fileName);
  void swap(ED2KHash& o);
  std::string getFileHash();
  friend std::ostream& operator<<(std::ostream& out, const ED2KHash& v);
   
private:
  int m_mode;
  size_t m_fileSize;
  std::string m_fileName;
  std::string m_fileHash;
   
  void copy(const ED2KHash& o);
#if __cplusplus >= 201103L
  void move(ED2KHash& o);
#endif
};
 
END_NAMESPACE_MYCODE
 
#endif 

ED2KHash. CPP


#include <cstring>
#include <fstream>
#include <utility>
#include "utils.h"
#include "MD4Hash.h"
#include "ED2KHash.h"
 
BEGIN_NAMESPACE_MYCODE
///////////////////////////////////////////////////////////////////////////////
//        ED2KHash                          //
///////////////////////////////////////////////////////////////////////////////
 
ED2KHash::ED2KHash(int mode)
 : m_mode(mode), m_fileSize(0)
{  }
 
void ED2KHash::copy(const ED2KHash& o)
{
  m_mode = o.m_mode;
  m_fileSize = o.m_fileSize;
  m_fileName = o.m_fileName;
  m_fileHash = o.m_fileHash;
}
 
ED2KHash::ED2KHash(const ED2KHash& o)
{
  copy(o);
}
 
ED2KHash& ED2KHash::operator=(const ED2KHash& o)
{
  copy(o);
  return *this;
}
 
#if __cplusplus >= 201103L
void ED2KHash::move(ED2KHash& o)
{
  m_mode = o.m_mode;
  m_fileSize = o.m_fileSize;
  m_fileName = std::move(o.m_fileName);
  m_fileHash = std::move(o.m_fileHash);
}
 
ED2KHash::ED2KHash(ED2KHash&& o)
{
  this->move(o);
}
 
ED2KHash& ED2KHash::operator=(ED2KHash&& o)
{
  this->move(o);
  return *this;
}
#endif
 
ED2KHash::~ED2KHash()
{  }
 
void ED2KHash::swap(ED2KHash& o)
{
  std::swap(*this, o);
}
 
std::string ED2KHash::getFileHash()
{
  return m_fileHash;
}
 
enum { CHUNK_SIZE = 9728000 };
enum { BLOCK_180K = 184320, BLOCK_140K = 143360 };
 
void ED2KHash::exec(const char* fileName)
{
  std::string msg("error: ");
   
  std::ifstream in(fileName, std::ios_base::binary | std::ios_base::in);
 if (!in.is_open())
    throw msg = msg + "Open '" + fileName + "' failed.";
   
  if ((m_fileSize = mc::getFileSize(in)) == 0)
  throw msg = msg + fileName + " is empty.";
   
  mc::getShortFileName(&m_fileName, fileName);
   
  static mc::MD4Hash md4Hash;
  static mc::MD4HashAlgo partHashMD4Algo, fileHashMD4Algo;
  fileHashMD4Algo.reset();
  static char chunk[CHUNK_SIZE];
  size_t readCount;
  size_t chunkCount = 0;
   
  bool bContinue = true;
  while (bContinue)
  {
   in.read(chunk, CHUNK_SIZE);
     
    if ((readCount = in.gcount()) < CHUNK_SIZE)
    {
      if (in.eof()) {
        if (0 == readCount)
          break;
        bContinue = false;
        memset(chunk + readCount, 0, CHUNK_SIZE - readCount);
      } else {
        throw msg += "Read file failed.";
      }
    }
    partHashMD4Algo.reset();
    partHashMD4Algo.update(chunk, readCount);
    partHashMD4Algo.finish();
    md4Hash = mc_move(partHashMD4Algo.getHash());
    fileHashMD4Algo.update(md4Hash);
     
    /*if (m_mode & PartHash) {
      if (bWriteToData)
        ;//
      else {
        md4Hash.setBigEndian();
        m_listPartHash.push_back(md4Hash);
      }
    }*/
    if (m_mode & RootHash) {
      //
    }
     
    chunkCount++;
  }
   
  if (chunkCount > 1) {
    fileHashMD4Algo.finish();
    md4Hash = mc_move(fileHashMD4Algo.getHash());
    md4Hash.setBigEndian();
    m_fileHash = mc_move(md4Hash.toString());
  } else {
    md4Hash = mc_move(partHashMD4Algo.getHash());
    md4Hash.setBigEndian();
    m_fileHash = mc_move(md4Hash.toString());
  }
}
 
std::ostream& operator<<(std::ostream& out, const ED2KHash& v)
{
  out << "ed2k://|file|" << v.m_fileName << '|' << v.m_fileSize << '|'
    << v.m_fileHash << '|';
   
  
  //if (v.m_mode | ED2KHash::RootHash)
  // out << '|';
   
  return out << '/';
}
 
END_NAMESPACE_MYCODE

Ed2k. CPP


#include <cstdlib>
#include <cstring>
#include <string>
#include <iostream>
#include <fstream>
#include "utils.h"
#include "ED2KHash.h"
#include "defs.h"
 
void usage(bool b)
{
  std::cout
   << "command: ed2k [Option...] <File...>n"
   << "     ed2k <File...>      (1)n"
   << "     ed2k -r <File...>    (2)n"
   << "     ed2k -p <File...>    (3)n"
    << "     ed2k -p -r <File...>   (4)n"
    << "     ed2k -pr <File...>    (4)nn"
 
   << "(1) ed2k://|file|<FileName>|<FileSize>|<FileHash>|/n"
    << "(2) ed2k://|file|<FileName>|<FileSize>|<FileHash>|<h=RootHash>|/n"
    << "(3) ed2k://|file|<FileName>|<FileSize>|<FileHash>|<p=PartHash>|/n"
  << "(4) ed2k://|file|<FileName>|<FileSize>|<FileHash>|<p=PartHash>|<h=RootHash>|/"
 << std::endl;
     
  if (b)
    exit(EXIT_SUCCESS);
}
 
bool parsed(int argc, const char *argv[], int *opt, int *pos)
{
  if (argc < 2)
    return false;
   
  if (strcmp("--help", argv[1]) == 0)
    usage(true);
  if (strcmp("--version", argv[1]) == 0)
  {  
    std::cout << "0.1v" << std::endl;
    exit(EXIT_SUCCESS);
  }
   
  *opt = mc::ED2KHash::FileHash;
  *pos = 1;
  for (; *pos < argc; ++(*pos))
  {
    if ('-' != argv[*pos][0])
      break;
     
    int len = strlen(argv[*pos]);
    for(int j = 1; j < len; ++j)
    {
      if ('p' == argv[*pos][j])
        *opt |= mc::ED2KHash::PartHash;
      else if ('r' == argv[*pos][j])
        *opt |= mc::ED2KHash::RootHash;
      else {
        std::cerr << "error: '" << argv[*pos] << "' is not a option."
         << " Enter '--help' veiw usage." << std::endl;
        return false;
      }
    }
  }
  if (*pos == argc)
  {
    std::cerr << "error: no parameter."
     << " Enter '--help' veiw usage." << std::endl;
    return false;
  }
  return true;
}
 
int main(int argc, const char *argv[])
{ 
  int opt, pos;
 if (!parsed(argc, argv, &opt, &pos))
    exit(EXIT_FAILURE);
   
 int linkCount = 0;
  mc::ED2KHash ed2k(opt);
 for (; pos < argc; ++pos)
 {
  try {
      ed2k.exec(argv[pos]);
      std::cout << ed2k << std::endl;
    } catch (std::string& e) {
      std::cerr << e << "ncreated " << linkCount << " links." << std::endl;
      exit(EXIT_FAILURE);
  }
  linkCount++;
 }
 std::cerr << "ncreated " << linkCount << " links." << std::endl;
 exit(EXIT_SUCCESS);
}

Above is the article to share the production of ed2k chain code, I hope you can like.


Related articles: