1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2002 - 2007 by Björn Stenberg
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
28 #include "gigabeats.h"
30 #include "telechips.h"
32 #include "iaudio_bl_flash.h"
34 static int iaudio_encode(char *iname
, char *oname
, char *idstring
);
35 static int ipod_encode(char *iname
, char *oname
, int fw_ver
, bool fake_rsrc
);
36 static int ccpmp_encode(char *iname
, char *oname
);
40 ARCHOS_PLAYER
, /* and V1 recorder */
47 static unsigned int size_limit
[] =
49 0x32000, /* ARCHOS_PLAYER */
50 0x64000, /* ARCHOS_V2RECORDER */
51 0x64000, /* ARCHOS_FMRECORDER */
52 0x64000, /* ARCHOS_ONDIO_SP */
53 0x64000 /* ARCHOS_ONDIO_FM */
56 void short2le(unsigned short val
, unsigned char* addr
)
59 addr
[1] = (val
>> 8) & 0xff;
62 unsigned int le2int(unsigned char* buf
)
64 unsigned int res
= (buf
[3] << 24) | (buf
[2] << 16) | (buf
[1] << 8) | buf
[0];
69 void int2le(unsigned int val
, unsigned char* addr
)
72 addr
[1] = (val
>> 8) & 0xff;
73 addr
[2] = (val
>> 16) & 0xff;
74 addr
[3] = (val
>> 24) & 0xff;
77 void int2be(unsigned int val
, unsigned char* addr
)
79 addr
[0] = (val
>> 24) & 0xff;
80 addr
[1] = (val
>> 16) & 0xff;
81 addr
[2] = (val
>> 8) & 0xff;
85 void short2be(unsigned short val
, unsigned char* addr
)
87 addr
[0] = (val
>> 8) & 0xff;
93 printf("usage: scramble [options] <input file> <output file> [xor string]\n");
95 "\t-fm Archos FM recorder format\n"
96 "\t-v2 Archos V2 recorder format\n"
97 "\t-ofm Archos Ondio FM recorder format\n"
98 "\t-osp Archos Ondio SP format\n"
99 "\t-neo SSI Neo format\n"
100 "\t-mm=X Archos Multimedia format (X values: A=JBMM, B=AV1xx, C=AV3xx)\n"
101 "\t-iriver iRiver format\n"
102 "\t-iaudiox5 iAudio X5 format\n"
103 "\t-iaudiox5v iAudio X5V format\n"
104 "\t-iaudiom5 iAudio M5 format\n"
105 "\t-iaudiom3 iAudio M3 format\n");
106 printf("\t-ipod3g ipod firmware partition format (3rd Gen)\n"
107 "\t-ipod4g ipod firmware partition format (4th Gen, Mini, Nano, Photo/Color)\n"
108 "\t-ipod5g ipod firmware partition format (5th Gen - aka Video)\n"
109 "\t-creative=X Creative firmware structure format\n"
110 "\t (X values: zvm, zvm60, zenvision\n"
112 printf("\t-gigabeat Toshiba Gigabeat F/X format\n"
113 "\t-gigabeats Toshiba Gigabeat S format\n"
114 "\t-mi4v2 PortalPlayer .mi4 format (revision 010201)\n"
115 "\t-mi4v3 PortalPlayer .mi4 format (revision 010301)\n"
116 "\t-mi4r Sandisk Rhapsody .mi4 format\n"
117 "\t All mi4 options take two optional arguments:\n");
118 printf("\t -model=XXXX where XXXX is the model id string\n"
119 "\t -type=XXXX where XXXX is a string indicating the \n"
120 "\t type of binary, eg. RBOS, RBBL\n"
121 "\t-tcc=X Telechips generic firmware format (X values: sum, crc)\n"
122 "\t-add=X Rockbox generic \"add-up\" checksum format\n"
123 "\t (X values: h100, h120, h140, h300, ipco, nano, ipvd, mn2g\n"
124 "\t ip3g, ip4g, mini, iax5, iam5, iam3, h10, h10_5gb,\n"
125 "\t tpj2, c200, e200, giga, gigs, m100, m500, d2,\n");
126 printf("\t 9200, 1630, 6330, ldax, m200, c100, clip, e2v2,\n"
127 "\t m2v4, fuze, c2v2, clv2, y820, y920, y925, x747,\n"
128 "\t 747p, x777, nn2g, m244, cli+, fuz2, hd20, hd30,\n"
129 "\t ip6g, rk27, clzp)\n");
130 printf("\nNo option results in Archos standard player/recorder format.\n");
135 int main (int argc
, char** argv
)
137 unsigned long length
,i
,slen
=0;
138 unsigned char *inbuf
,*outbuf
;
139 unsigned short crc
=0;
140 unsigned long chksum
=0; /* 32 bit checksum */
141 unsigned char header
[24];
142 char *iname
= argv
[1];
143 char *oname
= argv
[2];
144 char *xorstring
=NULL
;
148 unsigned long modelnum
;
151 enum { none
, scramble
, xor, tcc_sum
, tcc_crc
, add
} method
= scramble
;
152 bool creative_enable_ciff
;
154 model_id
= ARCHOS_PLAYER
;
160 if(!strcmp(argv
[1], "-fm")) {
165 model_id
= ARCHOS_FMRECORDER
;
168 else if(!strcmp(argv
[1], "-v2")) {
173 model_id
= ARCHOS_V2RECORDER
;
176 else if(!strcmp(argv
[1], "-ofm")) {
181 model_id
= ARCHOS_ONDIO_FM
;
184 else if(!strcmp(argv
[1], "-osp")) {
189 model_id
= ARCHOS_ONDIO_SP
;
192 else if(!strcmp(argv
[1], "-neo")) {
198 else if(!strncmp(argv
[1], "-mm=", 4)) {
203 version
= argv
[1][4];
207 printf("Multimedia needs an xor string\n");
211 else if(!strncmp(argv
[1], "-tcc=", 4)) {
216 if(!strcmp(&argv
[1][5], "sum"))
218 else if(!strcmp(&argv
[1][5], "crc"))
221 fprintf(stderr
, "unsupported TCC method: %s\n", &argv
[1][5]);
225 else if(!strncmp(argv
[1], "-add=", 5)) {
230 if(!strcmp(&argv
[1][5], "h120"))
232 else if(!strcmp(&argv
[1][5], "h140"))
233 modelnum
= 0; /* the same as the h120 */
234 else if(!strcmp(&argv
[1][5], "h100"))
236 else if(!strcmp(&argv
[1][5], "h300"))
238 else if(!strcmp(&argv
[1][5], "ipco"))
240 else if(!strcmp(&argv
[1][5], "nano"))
242 else if(!strcmp(&argv
[1][5], "ipvd"))
244 else if(!strcmp(&argv
[1][5], "fp7x"))
246 else if(!strcmp(&argv
[1][5], "ip3g"))
248 else if(!strcmp(&argv
[1][5], "ip4g"))
250 else if(!strcmp(&argv
[1][5], "mini"))
252 else if(!strcmp(&argv
[1][5], "iax5"))
254 else if(!strcmp(&argv
[1][5], "mn2g"))
256 else if(!strcmp(&argv
[1][5], "h10"))
258 else if(!strcmp(&argv
[1][5], "h10_5gb"))
260 else if(!strcmp(&argv
[1][5], "tpj2"))
262 else if(!strcmp(&argv
[1][5], "e200"))
264 else if(!strcmp(&argv
[1][5], "iam5"))
266 else if(!strcmp(&argv
[1][5], "giga"))
268 else if(!strcmp(&argv
[1][5], "1g2g"))
270 else if(!strcmp(&argv
[1][5], "c200"))
272 else if(!strcmp(&argv
[1][5], "gigs"))
274 else if(!strcmp(&argv
[1][5], "m500"))
276 else if(!strcmp(&argv
[1][5], "m100"))
278 else if(!strcmp(&argv
[1][5], "d2"))
280 else if(!strcmp(&argv
[1][5], "iam3"))
282 else if (!strcmp(&argv
[1][5], "m200"))
284 else if(!strcmp(&argv
[1][5], "c100"))
286 else if(!strcmp(&argv
[1][5], "1630")) /* Philips HDD1630 */
288 else if (!strcmp(&argv
[1][5], "i7"))
290 else if (!strcmp(&argv
[1][5], "ldax"))
292 else if(!strcmp(&argv
[1][5], "9200")) /* Philips SA9200 */
294 else if (!strcmp(&argv
[1][5], "clip"))
296 else if (!strcmp(&argv
[1][5], "e2v2"))
298 else if (!strcmp(&argv
[1][5], "m2v4"))
300 else if (!strcmp(&argv
[1][5], "fuze"))
302 else if (!strcmp(&argv
[1][5], "c2v2"))
304 else if (!strcmp(&argv
[1][5], "x747"))
306 else if (!strcmp(&argv
[1][5], "747p"))
308 else if (!strcmp(&argv
[1][5], "y820")) /* Samsung YH-820 */
310 else if (!strcmp(&argv
[1][5], "y920")) /* Samsung YH-920 */
312 else if (!strcmp(&argv
[1][5], "y925")) /* Samsung YH-925 */
314 else if (!strcmp(&argv
[1][5], "clv2")) /* Sansa Clipv2 */
316 else if (!strcmp(&argv
[1][5], "x777"))
318 else if (!strcmp(&argv
[1][5], "nn2g")) /* iPod Nano 2nd Gen */
320 else if (!strcmp(&argv
[1][5], "x767"))
322 else if (!strcmp(&argv
[1][5], "6330")) /* Philips HDD6330 */
324 else if (!strcmp(&argv
[1][5], "cli+")) /* Sansa Clip+ */
326 else if (!strcmp(&argv
[1][5], "v500")) /* Packard Bell Vibe 500 */
328 else if (!strcmp(&argv
[1][5], "fuz2")) /* Sansa Fuze v2 */
330 else if (!strcmp(&argv
[1][5], "m244"))
332 else if (!strcmp(&argv
[1][5], "hd20")) /* MPIO HD200 */
334 else if (!strcmp(&argv
[1][5], "hd30")) /* MPIO HD300 */
336 else if (!strcmp(&argv
[1][5], "ip6g")) /* iPod Classic/6G */
338 else if (!strcmp(&argv
[1][5], "fuz+")) /* Sansa Fuze+ */
340 else if (!strcmp(&argv
[1][5], "rk27")) /* rockchip 27xx generic */
342 else if (!strcmp(&argv
[1][5], "clzp")) /* Sansa Clip Zip */
344 else if (!strcmp(&argv
[1][5], "conn")) /* Sansa Connect */
347 fprintf(stderr
, "unsupported model: %s\n", &argv
[1][5]);
350 /* we store a 4-letter model name too, for humans */
351 strncpy(modelname
, &argv
[1][5],4);
352 modelname
[4] = '\0'; /* to be sure we are null terminated */
353 chksum
= modelnum
; /* start checksum calcs with this */
356 else if(!strcmp(argv
[1], "-iriver")) {
357 /* iRiver code dealt with in the iriver.c code */
360 return (iriver_encode(iname
, oname
, FALSE
) != 0) ? -1 : 0;
362 else if(!strcmp(argv
[1], "-gigabeat")) {
363 /* iRiver code dealt with in the iriver.c code */
366 gigabeat_code(iname
, oname
);
369 else if(!strcmp(argv
[1], "-gigabeats")) {
372 return gigabeat_s_code(iname
, oname
);
374 else if(!strcmp(argv
[1], "-iaudiox5")) {
377 return iaudio_encode(iname
, oname
, "COWON_X5_FW");
379 else if(!strcmp(argv
[1], "-iaudiox5v")) {
382 return iaudio_encode(iname
, oname
, "COWON_X5V_FW");
384 else if(!strcmp(argv
[1], "-iaudiom5")) {
387 return iaudio_encode(iname
, oname
, "COWON_M5_FW");
389 else if(!strcmp(argv
[1], "-iaudiom3")) {
392 return iaudio_encode(iname
, oname
, "COWON_M3_FW");
394 else if(!strcmp(argv
[1], "-ipod3g")) {
397 return ipod_encode(iname
, oname
, 2, false); /* Firmware image v2 */
399 else if(!strcmp(argv
[1], "-ipod4g")) {
402 return ipod_encode(iname
, oname
, 3, false); /* Firmware image v3 */
404 else if(!strcmp(argv
[1], "-ipod5g")) {
407 return ipod_encode(iname
, oname
, 3, true); /* Firmware image v3 */
409 else if(!strncmp(argv
[1], "-creative=", 10)) {
410 if(!strcmp(argv
[2], "-no-ciff"))
412 creative_enable_ciff
= false;
418 creative_enable_ciff
= true;
422 if(!strcmp(&argv
[1][10], "zvm"))
423 return zvm_encode(iname
, oname
, ZENVISIONM
, creative_enable_ciff
);
424 else if(!strcmp(&argv
[1][10], "zvm60"))
425 return zvm_encode(iname
, oname
, ZENVISIONM60
, creative_enable_ciff
);
426 else if(!strcmp(&argv
[1][10], "zenvision"))
427 return zvm_encode(iname
, oname
, ZENVISION
, creative_enable_ciff
);
428 else if(!strcmp(&argv
[1][10], "zenv"))
429 return zvm_encode(iname
, oname
, ZENV
, creative_enable_ciff
);
430 else if(!strcmp(&argv
[1][10], "zen"))
431 return zvm_encode(iname
, oname
, ZEN
, creative_enable_ciff
);
434 fprintf(stderr
, "unsupported Creative device: %s\n", &argv
[1][10]);
438 else if(!strcmp(argv
[1], "-ccpmp")) {
441 return ccpmp_encode(iname
, oname
);
443 else if(!strncmp(argv
[1], "-mi4", 4)) {
448 if(!strcmp(&argv
[1][4], "v2")) {
449 mi4magic
= MI4_MAGIC_DEFAULT
;
450 version
= 0x00010201;
452 else if(!strcmp(&argv
[1][4], "v3")) {
453 mi4magic
= MI4_MAGIC_DEFAULT
;
454 version
= 0x00010301;
456 else if(!strcmp(&argv
[1][4], "r")) {
457 mi4magic
= MI4_MAGIC_R
;
458 version
= 0x00010301;
461 printf( "Invalid mi4 version: %s\n", &argv
[1][4]);
468 if(!strncmp(argv
[2], "-model=", 7)) {
471 strncpy(model
, &argv
[2][7], 4);
473 if(!strncmp(argv
[3], "-type=", 6)) {
476 strncpy(type
, &argv
[3][6], 4);
480 return mi4_encode(iname
, oname
, version
, mi4magic
, model
, type
);
484 file
= fopen(iname
,"rb");
489 fseek(file
,0,SEEK_END
);
490 length
= ftell(file
);
491 length
= (length
+ 3) & ~3; /* Round up to nearest 4 byte boundary */
493 if ((method
== scramble
) &&
494 ((length
+ headerlen
) >= size_limit
[model_id
])) {
495 printf("error: firmware image is %ld bytes while max size is %u!\n",
497 size_limit
[model_id
]);
502 fseek(file
,0,SEEK_SET
);
503 inbuf
= malloc(length
);
505 outbuf
= malloc(length
*2);
506 else if(method
== add
)
507 outbuf
= malloc(length
+ 8);
509 outbuf
= malloc(length
);
510 if ( !inbuf
|| !outbuf
) {
511 printf("out of memory!\n");
515 /* zero-fill the last 4 bytes to make sure there's no rubbish there
516 when we write the size-aligned file later */
517 memset(outbuf
+length
-4, 0, 4);
521 i
=fread(inbuf
,1,length
,file
);
531 for (i
= 0; i
< length
; i
++) {
532 /* add 8 unsigned bits but keep a 32 bit sum */
538 for (i
= 0; i
< length
; i
++) {
539 unsigned long addr
= (i
>> 2) + ((i
% 4) * slen
);
540 unsigned char data
= inbuf
[i
];
541 data
= ~((data
<< 1) | ((data
>> 7) & 1)); /* poor man's ROL */
549 for (i
=0; i
<length
; i
++) {
551 outbuf
[slen
++] = 0xff; /* all data is uncompressed */
552 outbuf
[slen
++] = inbuf
[i
];
557 /* dummy case just to silence picky compilers */
561 if((method
== none
) || (method
== scramble
) || (method
== xor)) {
562 /* calculate checksum */
563 for (i
=0;i
<length
;i
++)
567 memset(header
, 0, sizeof header
);
572 int2be(chksum
, header
); /* checksum, big-endian */
573 memcpy(&header
[4], modelname
, 4); /* 4 bytes model name */
574 memcpy(outbuf
, inbuf
, length
); /* the input buffer to output*/
580 memcpy(outbuf
, inbuf
, length
); /* the input buffer to output*/
581 telechips_encode_sum(outbuf
, length
);
585 memcpy(outbuf
, inbuf
, length
); /* the input buffer to output*/
586 telechips_encode_crc(outbuf
, length
);
590 if (headerlen
== 6) {
591 int2be(length
, header
);
592 header
[4] = (crc
>> 8) & 0xff;
593 header
[5] = crc
& 0xff;
599 header
[3] = 0xff; /* ??? */
601 header
[6] = (crc
>> 8) & 0xff;
602 header
[7] = crc
& 0xff;
604 header
[11] = version
;
606 header
[15] = headerlen
; /* really? */
608 int2be(length
, &header
[20]);
614 int xorlen
= strlen(xorstring
);
617 for (i
=0; i
<slen
; i
++)
618 outbuf
[i
] ^= xorstring
[i
& (xorlen
-1)];
620 /* calculate checksum */
621 for (i
=0; i
<slen
; i
++)
624 header
[0] = header
[2] = 'Z';
625 header
[1] = header
[3] = version
;
626 int2le(length
, &header
[4]);
627 int2le(slen
, &header
[8]);
628 int2le(crc
, &header
[12]);
633 #define MY_FIRMWARE_TYPE "Rockbox"
634 #define MY_HEADER_VERSION 1
636 strncpy((char *)header
, MY_FIRMWARE_TYPE
,9);
637 header
[9]='\0'; /*shouldn't have to, but to be SURE */
638 header
[10]=MY_HEADER_VERSION
&0xFF;
639 header
[11]=(crc
>>8)&0xFF;
641 int2be(sizeof(header
), &header
[12]);
646 file
= fopen(oname
,"wb");
652 if ( !fwrite(header
,headerlen
,1,file
) ) {
657 if ( !fwrite(outbuf
,length
,1,file
) ) {
669 static int iaudio_encode(char *iname
, char *oname
, char *idstring
)
674 unsigned char *outbuf
;
676 unsigned char sum
= 0;
678 file
= fopen(iname
, "rb");
683 fseek(file
,0,SEEK_END
);
684 length
= ftell(file
);
686 fseek(file
,0,SEEK_SET
);
687 outbuf
= malloc(length
+0x1030);
690 printf("out of memory!\n");
694 len
= fread(outbuf
+0x1030, 1, length
, file
);
695 if(len
< (size_t) length
) {
700 memset(outbuf
, 0, 0x1030);
701 strcpy((char *)outbuf
, idstring
);
702 memcpy(outbuf
+0x20, iaudio_bl_flash
,
703 BMPWIDTH_iaudio_bl_flash
* (BMPHEIGHT_iaudio_bl_flash
/8) * 2);
704 short2be(BMPWIDTH_iaudio_bl_flash
, &outbuf
[0x10]);
705 short2be((BMPHEIGHT_iaudio_bl_flash
/8), &outbuf
[0x12]);
708 for(i
= 0; i
< length
;i
++)
709 sum
+= outbuf
[0x1030 + i
];
711 int2be(length
, &outbuf
[0x1024]);
712 outbuf
[0x102b] = sum
;
716 file
= fopen(oname
, "wb");
722 len
= fwrite(outbuf
, 1, length
+0x1030, file
);
723 if(len
< (size_t)length
) {
733 /* Create an ipod firmware partition image
735 fw_ver = 2 for 3rd Gen ipods, 3 for all later ipods including 5g.
737 This function doesn't yet handle the Broadcom resource image for the 5g,
738 so the resulting images won't be usable.
740 This has also only been tested on an ipod Photo
743 static int ipod_encode(char *iname
, char *oname
, int fw_ver
, bool fake_rsrc
)
745 static const char *apple_stop_sign
= "{{~~ /-----\\ "\
766 unsigned int sum
= 0;
767 unsigned int rsrcsum
= 0;
768 unsigned char *outbuf
;
772 file
= fopen(iname
, "rb");
777 fseek(file
,0,SEEK_END
);
778 length
= ftell(file
);
780 fseek(file
,0,SEEK_SET
);
782 bufsize
=(length
+0x4600);
784 bufsize
= (bufsize
+ 0x400) & ~0x200;
787 outbuf
= malloc(bufsize
);
790 printf("out of memory!\n");
794 len
= fread(outbuf
+0x4600, 1, length
, file
);
795 if(len
< (size_t)length
) {
801 /* Calculate checksum for later use in header */
802 for(i
= 0x4600; i
< 0x4600+length
;i
++)
805 /* Clear the header area to zero */
806 memset(outbuf
, 0, 0x4600);
808 /* APPLE STOP SIGN */
809 strcpy((char *)outbuf
, apple_stop_sign
);
812 memcpy(&outbuf
[0x100],"]ih[",4); /* Magic */
813 int2le(0x4000, &outbuf
[0x104]); /* Firmware offset relative to 0x200 */
814 short2le(0x10c, &outbuf
[0x108]); /* Location of extended header */
815 short2le(fw_ver
, &outbuf
[0x10a]);
817 /* Firmware Directory - "osos" entry */
818 memcpy(&outbuf
[0x4200],"!ATAsoso",8); /* dev and type */
819 int2le(0, &outbuf
[0x4208]); /* id */
820 int2le(0x4400, &outbuf
[0x420c]); /* devOffset */
821 int2le(length
, &outbuf
[0x4210]); /* Length of firmware */
822 int2le(0x10000000, &outbuf
[0x4214]); /* Addr */
823 int2le(0, &outbuf
[0x4218]); /* Entry Offset */
824 int2le(sum
, &outbuf
[0x421c]); /* Checksum */
825 int2le(0x00006012, &outbuf
[0x4220]); /* vers - 0x6012 is a guess */
826 int2le(0xffffffff, &outbuf
[0x4224]); /* LoadAddr - for flash images */
828 /* "rsrc" entry (if applicable) */
830 rsrcoffset
=(length
+0x4600+0x200) & ~0x200;
834 memcpy(&outbuf
[0x4228],"!ATAcrsr",8); /* dev and type */
835 int2le(0, &outbuf
[0x4230]); /* id */
836 int2le(rsrcoffset
, &outbuf
[0x4234]); /* devOffset */
837 int2le(rsrclength
, &outbuf
[0x4238]); /* Length of firmware */
838 int2le(0x10000000, &outbuf
[0x423c]); /* Addr */
839 int2le(0, &outbuf
[0x4240]); /* Entry Offset */
840 int2le(rsrcsum
, &outbuf
[0x4244]); /* Checksum */
841 int2le(0x0000b000, &outbuf
[0x4248]); /* vers */
842 int2le(0xffffffff, &outbuf
[0x424c]); /* LoadAddr - for flash images */
845 file
= fopen(oname
, "wb");
851 len
= fwrite(outbuf
, 1, length
+0x4600, file
);
852 if(len
< (size_t)length
) {
862 #define CCPMP_SIZE 0x500000
863 static int ccpmp_encode(char *iname
, char *oname
)
868 unsigned char *outbuf
;
870 file
= fopen(iname
, "rb");
875 fseek(file
,0,SEEK_END
);
876 length
= ftell(file
);
878 fseek(file
,0,SEEK_SET
);
880 outbuf
= malloc(CCPMP_SIZE
);
883 printf("out of memory!\n");
887 len
= fread(outbuf
, 1, length
, file
);
888 if(len
< (size_t)length
) {
894 /* Clear the tail area to 0xFF */
895 memset(&outbuf
[length
], 0xFF, CCPMP_SIZE
- length
);
898 int2le(length
, &outbuf
[0x4]);
900 file
= fopen(oname
, "wb");
906 len
= fwrite(outbuf
, 1, CCPMP_SIZE
, file
);
907 if(len
< (size_t)length
) {