/* Wrapster file archiver client for XAD.
 * Copyright (C) 2000 Stuart Caie <kyzer@4u.net>
 *
 * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

/* Wrapster is a way of using the Napster MP3 sharing system to not only
 * share MP3s, but any files you like.
 * See http://members.fortunecity.com/wrapster/ for more information.
 *
 * The CRC32 feature of Wrapster is ignored completely, for two reasons:
 * - the Wrapster authors haven't told anybody what the CRC calculation is
 * - because of this, other wrapper authors have used different CRCs!!!!
 * Therefore, there's no real point checking.
 */

/* From the Wrapster 2.0 .HLP file:
 * Wrapster File Format for v1.0 and v2.0
 *
 * Ok... here is the official specification for the layout of a Wrapster
 * file. This section is intended for programmers and anyone who might be
 * curious about how this whole thing works. The reasons for including this
 * specification is to encourage other programmers to write their own
 * Wrapster clones for other Operating Systems, or to extend the features
 * of the Windows version of Wrapster itself. If you extend the features of
 * Wrapster, use some of the unused bytes so that your client can easily
 * identify those files which it creates.
 * 
 * A Wrapster file will have the following format on disk:
 * 
 * Header
 *   FrameHeader           4 bytes         0xFF, 0xFB, 0x18, 0x0C
 *   Reserved (Unused)     6 bytes
 *   Signature             10 bytes        "wrapster"#0#0
 *   Version               8 bytes         "2.0"#0#0#0#0#0
 *   FileCount             4 bytes
 * 
 * Wrapster File Entry
 * 
 * Immediately following the header of the file you will find FileCount
 * entries each containing the following data
 * 
 *   OriginalFileName      256 bytes
 *   Reserved (Unused)     32 bytes
 *   CRC32                 4 bytes
 *   Size                  4 bytes
 *   FileData              Size bytes
 * 
 * Padding
 * 
 * After all file entries in the Wrapster file you will encounter padding
 * that helps to assure that the files contained within the archive remain
 * intact. This was done as a precaution since many downloads across
 * Napster tend to get the last few bytes cut off.
 * 
 * ID3 Tag
 * The last 128 bytes of the padding contain an MP3 identification tag that
 * will show up in the play-list of programs like Winamp as an ID3 tag. You
 * may put any values in here that you like. See the MP3 specification for
 * more information.
 */

#include "SDI_compiler.h"
#include "ConvertE.c"
#include <exec/types.h>
#include <exec/memory.h>
#include <string.h>
#include <libraries/xadmaster.h>
#include <proto/xadmaster.h>


#ifndef XADMASTERFILE
#define Wrap_Client		FirstClient
#define NEXTCLIENT		0
const UBYTE version[] = "$VER: Wrapster 1.1 (05.08.2000)";
#endif
#define WRAP_VERSION		1
#define WRAP_REVISION		1

#define XADBASE  REG(a6, struct xadMasterBase *xadMasterBase)


#define head_magic      (0x00)
#define head_reserved   (0x04)
#define head_signature  (0x0a)
#define head_version    (0x14)
#define head_filecount  (0x1c)
#define head_SIZEOF     (0x20)

#define file_name       (0x000)
#define file_reserved   (0x100)
#define file_crc32      (0x120)
#define file_size       (0x124)
#define file_SIZEOF     (0x128)

ASM(BOOL) Wrap_RecogData(REG(d0, ULONG size), REG(a0, STRPTR d), XADBASE) {
  return (BOOL) (d[0]==0xFF && d[1]==0xFB && d[2]==0x18 && d[3]==0x0C
                 && memcmp(d+10, "wrapster\0\0", 10) == 0) ? 1 : 0;
}

ASM(LONG) Wrap_GetInfo(REG(a0, struct xadArchiveInfo *ai), XADBASE) {
  ULONG filenum = 1, numfiles;
  struct xadFileInfo *link = NULL,  *fi;
  LONG err = XADERR_OK;
  UBYTE buffer[296], *p;

  struct TagItem filetags[]  = {
    { XAD_OBJNAMESIZE, 257 },
    { TAG_DONE, 0 }
  };

  struct TagItem datetags[] = {
    { XAD_DATECURRENTTIME, 1 },
    { XAD_GETDATEXADDATE,  0 },
    { TAG_DONE, 0 }
  };

  /* read the file header */
  if ((err = xadHookAccess(XADAC_READ, head_SIZEOF, buffer, ai))) return err;

  /* check the version - is it "1.0" or "2.0" ? */
  if (buffer[head_version] != '1' && buffer[head_version] != '2') {
    return XADERR_DATAFORMAT;
  }

  /* get the number of files in this archive */
  numfiles = EndGetI32(buffer+head_filecount);

  while (numfiles--) {
    /* read the file header */
    if ((err = xadHookAccess(XADAC_READ, file_SIZEOF, buffer, ai))) break;

    fi = (struct xadFileInfo *) xadAllocObjectA(XADOBJ_FILEINFO, filetags);
    if (!fi) { err = XADERR_NOMEMORY; break; }

    fi->xfi_EntryNumber = filenum++;
    fi->xfi_Size        = EndGetI32(buffer+file_size);
    fi->xfi_Flags       = XADFIF_SEEKDATAPOS;
    fi->xfi_DataPos     = ai->xai_InPos;

    /* copy filename */
    xadCopyMem(buffer+file_name, fi->xfi_FileName, 256);
    fi->xfi_FileName[256] = '\0';

    fi->xfi_CrunchSize = fi->xfi_Size;

    /* fix MS-DOS filenames */
    for (p = fi->xfi_FileName; *p; p++) if (*p == '\\') *p = '/';

    /* fill in today's date */
    datetags[1].ti_Data = (ULONG) &fi->xfi_Date;
    xadConvertDatesA(datetags);

    if (link) link->xfi_Next = fi; else ai->xai_FileInfo = fi;
    link = fi;

    if ((err = xadHookAccess(XADAC_INPUTSEEK, fi->xfi_Size, NULL, ai))) break;
  }

  if (err) {
    if (!ai->xai_FileInfo) return err;
    ai->xai_Flags |= XADAIF_FILECORRUPT;
    ai->xai_LastError = err;
  }
  return XADERR_OK;
}

ASM(LONG) Wrap_UnArchive(REG(a0, struct xadArchiveInfo *ai), XADBASE) {
  return xadHookAccess(XADAC_COPY, ai->xai_CurFile->xfi_Size, NULL, ai);
}

const struct xadClient Wrap_Client = {
  NEXTCLIENT, XADCLIENT_VERSION, 6, WRAP_VERSION, WRAP_REVISION,
  32, XADCF_FILEARCHIVER | XADCF_FREEFILEINFO,
  0, "Wrapster",

  /* client functions */
  (BOOL (*)()) Wrap_RecogData,
  (LONG (*)()) Wrap_GetInfo,
  (LONG (*)()) Wrap_UnArchive,
  NULL
};
