#include <stdio.h>
#include <string.h>

#include <sha.h>

#define MAXMSG 16000

int main(int argc, char *argv[])
{
  FILE *ofp = NULL;
  unsigned char ibuf[MAXMSG + 1024], bbuf[4], hbuf[4];
  unsigned char hashck[20], hck[20];
  unsigned int count = 0, len2;
  int len;
  char outf[16];
  SHA_CTX hash, hashall;
  int process = 0;

  /* these will return negative (or 128..255) if we don't have the end yet, 
     or return 1 if we are missing a middle piece (or the file is damaged) 
     zero means we have all the pieces and the final hash is good */

  if (argc > 1) {
    if (!strcmp(argv[1], "final"))
      process = 2;
    ofp = fopen("result.out", "w");
    if (!strcmp(argv[1], "test"))
      process = 1;
  }
  if (process)
    SHA1_Init(&hashall);

  for (;;) {
    memset(ibuf, 0, MAXMSG + 1024);

    if ((len = fread(hbuf, 1, 4, stdin)) <= 0)
      return -7 * process;
    count = hbuf[0] * 256 + hbuf[1];
    len2 = hbuf[2] * 256 + hbuf[3];

    if (len2 > MAXMSG)
      return -2;
    if ((len = fread(bbuf, 1, 4, stdin)) <= 0)
      return -3;
    if ((len = fread(hashck, 1, 20, stdin)) <= 0)
      return -4;
    len = len2;
    if (!len)
      len = 20;
    if ((len = fread(ibuf, 1, len, stdin)) < 0)
      return -5;

    if (process) {
      if (len2)
        SHA1_Update(&hashall, ibuf, len2);
      else {
        SHA1_Final(hck, &hashall);
        break;
      }
    } else {
      SHA1_Init(&hash);
      SHA1_Update(&hash, ibuf, len);
      SHA1_Final(hck, &hash);

      if (memcmp(hck, hashck, 20))
        return -7;

      sprintf(outf, "%08X.%03d", *((unsigned int *) (bbuf)), count);

      ofp = fopen(outf, "w");
      fwrite(hbuf, 1, 4, ofp);
      fwrite(bbuf, 1, 4, ofp);
      fwrite(hashck, 1, 20, ofp);
    }
    if (!(process & 1))
      fwrite(ibuf, 1, process ? len2 : len, ofp);
    if (!process)
      fclose(ofp);

  }

  if (process && memcmp(hck, ibuf, 20))  /* bad overall hash */
    return 1;
  return 0;
}
