1
0
Fork 0
forked from len0rd/rockbox

First commit:

* add Creative (ZVM, 60GB, ZV, ZVW, ZENV) support to scramble
* update configure to the correct values



git-svn-id: svn://svn.rockbox.org/rockbox/trunk@17042 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Maurus Cuelenaere 2008-04-09 11:53:28 +00:00
parent 5a3651bf94
commit e810721e72
7 changed files with 784 additions and 103 deletions

View file

@ -13,16 +13,18 @@ LDFLAGS := -g
CLEANALL := scramble descramble iriver sh2d bmp2rb rdf2binary convbdf \
generate_rocklatin mkboot ipod_fw codepages uclpack mi4 gigabeat database \
lngdump telechips gigabeats mktccboot mknkboot rbspeexenc
lngdump telechips gigabeats creative hmac-sha1 mktccboot mknkboot rbspeexenc
all:
@echo "Run make in your build directory!"
scramble: scramble.o iriver.o mi4.o gigabeat.o gigabeats.o telechips.o iaudio_bl_flash.o
scramble: scramble.o iriver.o mi4.o gigabeat.o gigabeats.o telechips.o iaudio_bl_flash.o creative.o hmac-sha1.o
descramble: descramble.o iriver.o gigabeat.o
scramble.o: scramble.c iriver.h mi4.h gigabeat.h telechips.h iaudio_bl_flash.h creative.h
scramble.o: scramble.c iriver.h mi4.h gigabeat.h telechips.h iaudio_bl_flash.h
descramble.o: descramble.c iriver.h gigabeat.h
creative.o: creative.c creative.h
hmac-sha1.o: hmac-sha1.c hmac-sha1.h
iriver.o: iriver.c iriver.h
gigabeat.o: gigabeat.c gigabeat.h
gigabeats.o: gigabeats.c gigabeats.h

9
tools/configure vendored
View file

@ -1455,18 +1455,19 @@ fi
target_id=35
modelname="creativezvm"
target="-DCREATIVE_ZVM"
memory=32 # always
memory=64
arm926ejscc
bmp2rb_mono="$rootdir/tools/bmp2rb -f 0"
bmp2rb_native="$rootdir/tools/bmp2rb -f 4"
bmp2rb_remotemono="$rootdir/tools/bmp2rb -f 0"
bmp2rb_remotenative="$rootdir/tools/bmp2rb -f 0"
tool="cp"
output="rockbox.zvm"
appextra="recorder:gui"
plugins="yes"
plugins=""
swcodec="yes"
toolset=$gigabeatbitmaptools
boottool="$rootdir/tools/scramble -zvm"
boottool="$rootdir/tools/scramble -creative=zvm"
bootoutput="rockbox.zvmboot"
# architecture, manufacturer and model for the target-tree build
t_cpu="arm"
@ -1998,7 +1999,7 @@ sed > Makefile \
-e "s,@VOICETOOLSET@,${voicetoolset},g" \
-e "s,@LANGS@,${buildlangs},g" \
<<EOF
## Automaticly generated. http://www.rockbox.org/
## Automatically generated. http://www.rockbox.org/
ifndef V
SILENT=@

159
tools/creative.c Normal file
View file

@ -0,0 +1,159 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2008 by Maurus Cuelenaere
*
* All files in this archive are subject to the GNU General Public License.
* See the file COPYING in the source tree root for full license agreement.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include "creative.h"
#include "hmac-sha1.h"
#include <stdio.h>
#include <stdbool.h>
/*
Create a Zen Vision:M FRESCUE structure file
*/
static int make_ciff_file(char *inbuf, int length, char *outbuf, int device)
{
memcpy(outbuf, "FFIC", 4);
int2le(length+90, &outbuf[4]);
memcpy(&outbuf[8], "FNIC", 4);
int2le(96, &outbuf[0xC]);
memcpy(&outbuf[0x10], devices[device].cinf, devices[device].cinf_size);
memset(&outbuf[0x10+devices[device].cinf_size], 0, 96 - devices[device].cinf_size);
memcpy(&outbuf[0x70], "ATAD", 4);
int2le(length+32, &outbuf[0x74]);
memcpy(&outbuf[0x78], "H\0j\0u\0k\0e\0b\0o\0x\0\x32\0.\0j\0r\0m", 32); /*Unicode encoded*/
memcpy(&outbuf[0x98], inbuf, length);
memcpy(&outbuf[0x98+length], "LLUN", 4);
int2le(20, &outbuf[0x98+length+4]);
/* Do checksum */
char key[20];
hmac_sha((char*)devices[device].null, strlen(devices[device].null), outbuf, 0x98+length, key, 20);
memcpy(&outbuf[0x98+length+8], key, 20);
return length+0x90+0x1C+8;
}
static int make_jrm_file(char *inbuf, int length, char *outbuf)
{
int i;
unsigned int sum = 0;
/* Calculate checksum for later use in header */
for(i=0; i<length; i+= 4)
sum += le2int(&inbuf[i]) + (le2int(&inbuf[i])>>16);
/* Clear the header area to zero */
memset(outbuf, 0, 0x18);
/* Header (EDOC) */
memcpy(outbuf, "EDOC", 4);
/* Total Size */
int2le(length+0x20, &outbuf[0x4]);
/* 4 bytes of zero */
/* Address = 0x900000 */
int2le(0x900000, &outbuf[0xC]);
/* Size */
int2le(length, &outbuf[0x10]);
/* Checksum */
int2le(sum, &outbuf[0x14]);
outbuf[0x16] = 0;
outbuf[0x17] = 0;
/* Data starts here... */
memcpy(&outbuf[0x18], inbuf, length);
/* Second block starts here ... */
/* Address = 0x0 */
/* Size */
int2le(0x4, &outbuf[0x18+length+0x4]);
/* Checksum */
outbuf[0x18+length+0x8] = 0xA9;
outbuf[0x18+length+0x9] = 0xD9;
/* Data: MOV PC, 0x900000 */
outbuf[0x18+length+0xC] = 0x09;
outbuf[0x18+length+0xD] = 0xF6;
outbuf[0x18+length+0xE] = 0xA0;
outbuf[0x18+length+0xF] = 0xE3;
return length+0x18+0x10;
}
int zvm_encode(char *iname, char *oname, int device)
{
size_t len;
int length;
FILE *file;
unsigned char *outbuf;
unsigned char *buf;
int i;
file = fopen(iname, "rb");
if (!file) {
perror(iname);
return -1;
}
fseek(file, 0, SEEK_END);
length = ftell(file);
fseek(file, 0, SEEK_SET);
buf = (unsigned char*)malloc(length);
if ( !buf ) {
printf("out of memory!\n");
return -1;
}
len = fread(buf, 1, length, file);
if(len < length) {
perror(iname);
return -2;
}
fclose(file);
outbuf = (unsigned char*)malloc(length+0x300);
if ( !outbuf ) {
free(buf);
printf("out of memory!\n");
return -1;
}
length = make_jrm_file(buf, len, outbuf);
free(buf);
buf = (unsigned char*)malloc(length+0x200);
memset(buf, 0, length+0x200);
length = make_ciff_file(outbuf, length, buf, device);
free(outbuf);
file = fopen(oname, "wb");
if (!file) {
free(buf);
perror(oname);
return -3;
}
len = fwrite(buf, 1, length, file);
if(len < length) {
free(buf);
perror(oname);
return -4;
}
free(buf);
fclose(file);
return 0;
}

53
tools/creative.h Normal file
View file

@ -0,0 +1,53 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2008 by Maurus Cuelenaere
*
* All files in this archive are subject to the GNU General Public License.
* See the file COPYING in the source tree root for full license agreement.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#ifndef CREATIVE_H_
#define CREATIVE_H_
enum
{
ZENVISIONM = 0,
ZENVISIONM60 = 1,
ZENVISION = 2,
ZENV = 3
};
static struct device_info
{
const char* cinf; /*Must be Unicode encoded*/
const int cinf_size;
const char* null;
} device_info;
static const char null_key_v1[] = "CTL:N0MAD|PDE0.SIGN.";
static const char null_key_v2[] = "CTL:N0MAD|PDE0.DPMP.";
static const char null_key_v3[] = "CTL:Z3N07|PDE0.DPMP.";
static const char null_key_v4[] = "CTL:N0MAD|PDE0.DPFP.";
static const struct device_info devices[] =
{
{"C\0r\0e\0a\0t\0i\0v\0e\0 \0Z\0e\0n\0 \0V\0i\0s\0i\0o\0n\0:\0M", 42, null_key_v2},
{"C\0r\0e\0a\0t\0i\0v\0e\0 \0Z\0e\0n\0 \0V\0i\0s\0i\0o\0n\0:\0M\0 \0G\0o\0!", 50, null_key_v2},
{"C\0r\0e\0a\0t\0i\0v\0e\0 \0Z\0e\0n\0 \0V\0i\0s\0i\0o\0n\0 \0©\0T\0L", 48, null_key_v2},
{"C\0r\0e\0a\0t\0i\0v\0e\0 \0Z\0E\0N\0 \0V", 42, null_key_v4}
};
int zvm_encode(char *iname, char *oname, int device);
#endif /*CREATIVE_H_*/

463
tools/hmac-sha1.c Normal file
View file

@ -0,0 +1,463 @@
/*
* sha1.c
*
* Description:
* This file implements the Secure Hashing Algorithm 1 as
* defined in FIPS PUB 180-1 published April 17, 1995.
*
* The SHA-1, produces a 160-bit message digest for a given
* data stream. It should take about 2**n steps to find a
* message with the same digest as a given message and
* 2**(n/2) to find any two messages with the same digest,
* when n is the digest size in bits. Therefore, this
* algorithm can serve as a means of providing a
* "fingerprint" for a message.
*
* Portability Issues:
* SHA-1 is defined in terms of 32-bit "words". This code
* uses <stdint.h> (included via "sha1.h" to define 32 and 8
* bit unsigned integer types. If your C compiler does not
* support 32 bit unsigned integers, this code is not
* appropriate.
*
* Caveats:
* SHA-1 is designed to work with messages less than 2^64 bits
* long. Although SHA-1 allows a message digest to be generated
* for messages of any number of bits less than 2^64, this
* implementation only works with messages with a length that is
* a multiple of the size of an 8-bit character.
*
*/
#include "hmac-sha1.h"
/*
* Define the SHA1 circular left shift macro
*/
#define SHA1CircularShift(bits,word) \
(((word) << (bits)) | ((word) >> (32-(bits))))
/* Local Function Prototyptes */
void SHA1PadMessage(SHA1Context *);
void SHA1ProcessMessageBlock(SHA1Context *);
/*
* SHA1Reset
*
* Description:
* This function will initialize the SHA1Context in preparation
* for computing a new SHA1 message digest.
*
* Parameters:
* context: [in/out]
* The context to reset.
*
* Returns:
* sha Error Code.
*
*/
int SHA1Reset(SHA1Context *context)
{
if (!context)
{
return shaNull;
}
context->Length_Low = 0;
context->Length_High = 0;
context->Message_Block_Index = 0;
context->Intermediate_Hash[0] = 0x67452301;
context->Intermediate_Hash[1] = 0xEFCDAB89;
context->Intermediate_Hash[2] = 0x98BADCFE;
context->Intermediate_Hash[3] = 0x10325476;
context->Intermediate_Hash[4] = 0xC3D2E1F0;
context->Computed = 0;
context->Corrupted = 0;
return shaSuccess;
}
/*
* SHA1Result
*
* Description:
* This function will return the 160-bit message digest into the
* Message_Digest array provided by the caller.
* NOTE: The first octet of hash is stored in the 0th element,
* the last octet of hash in the 19th element.
*
* Parameters:
* context: [in/out]
* The context to use to calculate the SHA-1 hash.
* Message_Digest: [out]
* Where the digest is returned.
*
* Returns:
* sha Error Code.
*
*/
int SHA1Result( SHA1Context *context,
uint8_t Message_Digest[SHA1HashSize])
{
int i;
if (!context || !Message_Digest)
{
return shaNull;
}
if (context->Corrupted)
{
return context->Corrupted;
}
if (!context->Computed)
{
SHA1PadMessage(context);
for(i=0; i<64; ++i)
{
/* message may be sensitive, clear it out */
context->Message_Block[i] = 0;
}
context->Length_Low = 0; /* and clear length */
context->Length_High = 0;
context->Computed = 1;
}
for(i = 0; i < SHA1HashSize; ++i)
{
Message_Digest[i] = context->Intermediate_Hash[i>>2]
>> 8 * ( 3 - ( i & 0x03 ) );
}
return shaSuccess;
}
/*
* SHA1Input
*
* Description:
* This function accepts an array of octets as the next portion
* of the message.
*
* Parameters:
* context: [in/out]
* The SHA context to update
* message_array: [in]
* An array of characters representing the next portion of
* the message.
* length: [in]
* The length of the message in message_array
*
* Returns:
* sha Error Code.
*
*/
int SHA1Input( SHA1Context *context,
const uint8_t *message_array,
unsigned length)
{
if (!length)
{
return shaSuccess;
}
if (!context || !message_array)
{
return shaNull;
}
if (context->Computed)
{
context->Corrupted = shaStateError;
return shaStateError;
}
if (context->Corrupted)
{
return context->Corrupted;
}
while(length-- && !context->Corrupted)
{
context->Message_Block[context->Message_Block_Index++] =
(*message_array & 0xFF);
context->Length_Low += 8;
if (context->Length_Low == 0)
{
context->Length_High++;
if (context->Length_High == 0)
{
/* Message is too long */
context->Corrupted = 1;
}
}
if (context->Message_Block_Index == 64)
{
SHA1ProcessMessageBlock(context);
}
message_array++;
}
return shaSuccess;
}
/*
* SHA1ProcessMessageBlock
*
* Description:
* This function will process the next 512 bits of the message
* stored in the Message_Block array.
*
* Parameters:
* None.
*
* Returns:
* Nothing.
*
* Comments:
* Many of the variable names in this code, especially the
* single character names, were used because those were the
* names used in the publication.
*
*
*/
void SHA1ProcessMessageBlock(SHA1Context *context)
{
const uint32_t K[] = { /* Constants defined in SHA-1 */
0x5A827999,
0x6ED9EBA1,
0x8F1BBCDC,
0xCA62C1D6
};
int t; /* Loop counter */
uint32_t temp; /* Temporary word value */
uint32_t W[80]; /* Word sequence */
uint32_t A, B, C, D, E; /* Word buffers */
/*
* Initialize the first 16 words in the array W
*/
for(t = 0; t < 16; t++)
{
W[t] = context->Message_Block[t * 4] << 24;
W[t] |= context->Message_Block[t * 4 + 1] << 16;
W[t] |= context->Message_Block[t * 4 + 2] << 8;
W[t] |= context->Message_Block[t * 4 + 3];
}
for(t = 16; t < 80; t++)
{
W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
}
A = context->Intermediate_Hash[0];
B = context->Intermediate_Hash[1];
C = context->Intermediate_Hash[2];
D = context->Intermediate_Hash[3];
E = context->Intermediate_Hash[4];
for(t = 0; t < 20; t++)
{
temp = SHA1CircularShift(5,A) +
((B & C) | ((~B) & D)) + E + W[t] + K[0];
E = D;
D = C;
C = SHA1CircularShift(30,B);
B = A;
A = temp;
}
for(t = 20; t < 40; t++)
{
temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1];
E = D;
D = C;
C = SHA1CircularShift(30,B);
B = A;
A = temp;
}
for(t = 40; t < 60; t++)
{
temp = SHA1CircularShift(5,A) +
((B & C) | (B & D) | (C & D)) + E + W[t] + K[2];
E = D;
D = C;
C = SHA1CircularShift(30,B);
B = A;
A = temp;
}
for(t = 60; t < 80; t++)
{
temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3];
E = D;
D = C;
C = SHA1CircularShift(30,B);
B = A;
A = temp;
}
context->Intermediate_Hash[0] += A;
context->Intermediate_Hash[1] += B;
context->Intermediate_Hash[2] += C;
context->Intermediate_Hash[3] += D;
context->Intermediate_Hash[4] += E;
context->Message_Block_Index = 0;
}
/*
* SHA1PadMessage
*
* Description:
* According to the standard, the message must be padded to an even
* 512 bits. The first padding bit must be a '1'. The last 64
* bits represent the length of the original message. All bits in
* between should be 0. This function will pad the message
* according to those rules by filling the Message_Block array
* accordingly. It will also call the ProcessMessageBlock function
* provided appropriately. When it returns, it can be assumed that
* the message digest has been computed.
*
* Parameters:
* context: [in/out]
* The context to pad
* ProcessMessageBlock: [in]
* The appropriate SHA*ProcessMessageBlock function
* Returns:
* Nothing.
*
*/
void SHA1PadMessage(SHA1Context *context)
{
/*
* Check to see if the current message block is too small to hold
* the initial padding bits and length. If so, we will pad the
* block, process it, and then continue padding into a second
* block.
*/
if (context->Message_Block_Index > 55)
{
context->Message_Block[context->Message_Block_Index++] = 0x80;
while(context->Message_Block_Index < 64)
{
context->Message_Block[context->Message_Block_Index++] = 0;
}
SHA1ProcessMessageBlock(context);
while(context->Message_Block_Index < 56)
{
context->Message_Block[context->Message_Block_Index++] = 0;
}
}
else
{
context->Message_Block[context->Message_Block_Index++] = 0x80;
while(context->Message_Block_Index < 56)
{
context->Message_Block[context->Message_Block_Index++] = 0;
}
}
/*
* Store the message length as the last 8 octets
*/
context->Message_Block[56] = context->Length_High >> 24;
context->Message_Block[57] = context->Length_High >> 16;
context->Message_Block[58] = context->Length_High >> 8;
context->Message_Block[59] = context->Length_High;
context->Message_Block[60] = context->Length_Low >> 24;
context->Message_Block[61] = context->Length_Low >> 16;
context->Message_Block[62] = context->Length_Low >> 8;
context->Message_Block[63] = context->Length_Low;
SHA1ProcessMessageBlock(context);
}
#define SHA_DIGESTSIZE 20
#define SHA_BLOCKSIZE 64
static void truncate
(
char* d1, /* data to be truncated */
char* d2, /* truncated data */
int len /* length in bytes to keep */
)
{
int i ;
for (i = 0 ; i < len ; i++) d2[i] = d1[i];
}
/* Function to compute the digest */
void
hmac_sha
(
char* k, /* secret key */
int lk, /* length of the key in bytes */
char* d, /* data */
int ld, /* length of data in bytes */
char* out, /* output buffer, at least "t" bytes */
int t
)
{
SHA1Context ictx, octx ;
char isha[SHA_DIGESTSIZE], osha[SHA_DIGESTSIZE] ;
char key[SHA_DIGESTSIZE] ;
char buf[SHA_BLOCKSIZE] ;
int i ;
if (lk > SHA_BLOCKSIZE) {
SHA1Context tctx ;
SHA1Reset(&tctx) ;
SHA1Input(&tctx, k, lk) ;
SHA1Result(&tctx, key) ;
k = key ;
lk = SHA_DIGESTSIZE ;
}
/**** Inner Digest ****/
SHA1Reset(&ictx) ;
/* Pad the key for inner digest */
for (i = 0 ; i < lk ; ++i) buf[i] = k[i] ^ 0x36 ;
for (i = lk ; i < SHA_BLOCKSIZE ; ++i) buf[i] = 0x36 ;
SHA1Input(&ictx, buf, SHA_BLOCKSIZE) ;
SHA1Input(&ictx, d, ld) ;
SHA1Result(&ictx, isha) ;
/**** Outter Digest ****/
SHA1Reset(&octx) ;
/* Pad the key for outter digest */
for (i = 0 ; i < lk ; ++i) buf[i] = k[i] ^ 0x5C ;
for (i = lk ; i < SHA_BLOCKSIZE ; ++i) buf[i] = 0x5C ;
SHA1Input(&octx, buf, SHA_BLOCKSIZE) ;
SHA1Input(&octx, isha, SHA_DIGESTSIZE) ;
SHA1Result(&octx, osha) ;
/* truncate and print the results */
t = t > SHA_DIGESTSIZE ? SHA_DIGESTSIZE : t ;
truncate(osha, out, t) ;
}

84
tools/hmac-sha1.h Normal file
View file

@ -0,0 +1,84 @@
/*
* sha1.h
*
* Description:
* This is the header file for code which implements the Secure
* Hashing Algorithm 1 as defined in FIPS PUB 180-1 published
* April 17, 1995.
*
* Many of the variable names in this code, especially the
* single character names, were used because those were the names
* used in the publication.
*
* Please read the file sha1.c for more information.
*
*/
#ifndef _SHA1_H_
#define _SHA1_H_
#include <stdint.h>
/*
* If you do not have the ISO standard stdint.h header file, then you
* must typdef the following:
* name meaning
* uint32_t unsigned 32 bit integer
* uint8_t unsigned 8 bit integer (i.e., unsigned char)
* int_least16_t integer of >= 16 bits
*
*/
#ifndef _SHA_enum_
#define _SHA_enum_
enum
{
shaSuccess = 0,
shaNull, /* Null pointer parameter */
shaInputTooLong, /* input data too long */
shaStateError /* called Input after Result */
};
#endif
#define SHA1HashSize 20
/*
* This structure will hold context information for the SHA-1
* hashing operation
*/
typedef struct SHA1Context
{
uint32_t Intermediate_Hash[SHA1HashSize/4]; /* Message Digest */
uint32_t Length_Low; /* Message length in bits */
uint32_t Length_High; /* Message length in bits */
/* Index into message block array */
int_least16_t Message_Block_Index;
uint8_t Message_Block[64]; /* 512-bit message blocks */
int Computed; /* Is the digest computed? */
int Corrupted; /* Is the message digest corrupted? */
} SHA1Context;
/*
* Function Prototypes
*/
int SHA1Reset( SHA1Context *);
int SHA1Input( SHA1Context *,
const uint8_t *,
unsigned int);
int SHA1Result( SHA1Context *,
uint8_t Message_Digest[SHA1HashSize]);
void
hmac_sha
(
char* k,
int lk,
char* d,
int ld,
char* out,
int t
);
#endif

View file

@ -26,6 +26,7 @@
#include "gigabeats.h"
#include "mi4.h"
#include "telechips.h"
#include "creative.h"
#include "iaudio_bl_flash.h"
int iaudio_encode(char *iname, char *oname, char *idstring);
@ -102,7 +103,7 @@ void usage(void)
"\t-ipod3g ipod firmware partition format (3rd Gen)\n"
"\t-ipod4g ipod firmware partition format (4th Gen, Mini, Nano, Photo/Color)\n"
"\t-ipod5g ipod firmware partition format (5th Gen - aka Video)\n"
"\t-zvm Zen Vision:M FRESCUE structure format\n"
"\t-creative=X Creative firmware structure format\n"
"\t-gigabeat Toshiba Gigabeat F/X format\n"
"\t-gigabeats Toshiba Gigabeat S format\n"
"\t-mi4v2 PortalPlayer .mi4 format (revision 010201)\n"
@ -332,10 +333,21 @@ int main (int argc, char** argv)
oname = argv[3];
return ipod_encode(iname, oname, 3, true); /* Firmware image v3 */
}
else if(!strcmp(argv[1], "-zvm")) {
else if(!strncmp(argv[1], "-creative=", 10)) {
iname = argv[2];
oname = argv[3];
return zvm_encode(iname, oname);
if(!strcmp(&argv[1][10], "zvm"))
return zvm_encode(iname, oname, ZENVISIONM);
else if(!strcmp(&argv[1][10], "zvm60"))
return zvm_encode(iname, oname, ZENVISIONM60);
else if(!strcmp(&argv[1][10], "zenvision"))
return zvm_encode(iname, oname, ZENVISION);
else if(!strcmp(&argv[1][10], "zenv"))
return zvm_encode(iname, oname, ZENV);
else {
fprintf(stderr, "unsupported Creative device: %s\n", &argv[1][10]);
return 2;
}
}
else if(!strncmp(argv[1], "-mi4", 4)) {
int mi4magic;
@ -752,96 +764,3 @@ int ipod_encode(char *iname, char *oname, int fw_ver, bool fake_rsrc)
return 0;
}
/* Create an Zen Vision:M FRESCUE structure file
*/
int zvm_encode(char *iname, char *oname)
{
size_t len;
int length;
FILE *file;
unsigned int sum = 0;
unsigned char *outbuf;
int i;
file = fopen(iname, "rb");
if (!file) {
perror(iname);
return -1;
}
fseek(file,0,SEEK_END);
length = ftell(file);
fseek(file,0,SEEK_SET);
outbuf = malloc(length+0x18+0x10);
if ( !outbuf ) {
printf("out of memory!\n");
return -1;
}
len = fread(outbuf+0x18, 1, length, file);
if(len < length) {
perror(iname);
return -2;
}
fclose(file);
/* Calculate checksum for later use in header */
for(i=0; i<length; i+= 4)
sum += le2int(&outbuf[0x18+i]) + (le2int(&outbuf[0x18+i])>>16);
/* Clear the header area to zero */
memset(outbuf, 0, 0x18);
/* Header (EDOC) */
memcpy((char*)outbuf, "EDOC", 4);
/* Total Size */
int2le(length+0x20, &outbuf[0x4]);
/* 4 bytes of zero */
/* Address = 0x900000 */
int2le(0x900000, &outbuf[0xC]);
/* Size */
int2le(length, &outbuf[0x10]);
/* Checksum */
int2le(sum, &outbuf[0x14]);
outbuf[0x16] = 0;
outbuf[0x17] = 0;
/* Data starts here... */
/* Second block starts here ... */
/* Address = 0x0 */
/* Size */
int2le(0x4, &outbuf[0x18+length+0x4]);
/* Checksum */
outbuf[0x18+length+0x8] = 0xB7;
outbuf[0x18+length+0x9] = 0xD5;
/* Data: LDR PC, =0x900000 */
outbuf[0x18+length+0xC] = 0x18;
outbuf[0x18+length+0xD] = 0xF0;
outbuf[0x18+length+0xE] = 0x9F;
outbuf[0x18+length+0xF] = 0xE5;
file = fopen(oname, "wb");
if (!file) {
perror(oname);
return -3;
}
len = fwrite(outbuf, 1, length+0x28, file);
if(len < length+0x18) {
perror(oname);
return -4;
}
free(outbuf);
fclose(file);
return 0;
}