2 *******************************************************************************
4 * Copyright (C) 2000-2003, International Business Machines
5 * Corporation and others. All Rights Reserved.
7 *******************************************************************************
10 * tab size: 8 (not used)
13 * created on: 2001mar05
14 * created by: Markus W. Scherer
15 * changes by: Yves Arrouye
17 * This tool takes an ICU common data file (icuxyz.dat),
18 * outputs a list of components,
19 * and writes one file per packaged data piece in the common file.
20 * This can be used to add, remove, or replace data.
25 #include "unicode/utypes.h"
26 #include "unicode/udata.h"
30 static uint8_t buffer
[100000], buffer2
[128*1024];
32 static const char *pname
;
34 static UOption options
[]={
36 /*1*/ UOPTION_HELP_QUESTION_MARK
,
37 /*2*/ UOPTION_DESTDIR
,
38 /*3*/ UOPTION_DEF(0, 'n', UOPT_NO_ARG
),
39 /*4*/ UOPTION_DEF("comment", 'C', UOPT_NO_ARG
),
43 compareFiles(const void *file1
, const void *file2
) {
44 /* sort by file offset */
45 int32_t diff
=*((int32_t *)file1
+1)-*((int32_t *)file2
+1);
47 return (int)(diff
>>15)|1;
54 copyFile(FILE *in
, int32_t offset
, int32_t size
, const char *dir
, const char *name
) {
59 if(0!=fseek(in
, offset
, SEEK_SET
)) {
60 fprintf(stderr
, "%s: cannot seek to position %ld for file \"%s\"\n", pname
,
65 uprv_strcpy(path
, dir
);
66 p
= path
+ strlen(path
);
67 if (p
[-1] != U_FILE_SEP_CHAR
) {
68 *p
++ = U_FILE_SEP_CHAR
;
72 out
=fopen(path
, "wb");
74 fprintf(stderr
, "%s: unable to open output file \"%s\"\n", pname
, path
);
78 /* copy the contents into the new, separate file */
79 while(size
>sizeof(buffer2
)) {
80 length
=(int32_t)fread(buffer2
, 1, sizeof(buffer2
), in
);
82 fprintf(stderr
, "%s: read error while copying output file \"%s\"\n", pname
, path
);
86 if(length
!=(int32_t)fwrite(buffer2
, 1, length
, out
)) {
87 fprintf(stderr
, "%s: write error while copying output file \"%s\"\n", pname
, path
);
94 length
=(int32_t)fread(buffer2
, 1, size
, in
);
96 fprintf(stderr
, "%s: read error while copying output file \"%s\"\n", pname
, path
);
100 if(length
!=(int32_t)fwrite(buffer2
, 1, length
, out
)) {
101 fprintf(stderr
, "%s: write error while copying output file \"%s\"\n", pname
, path
);
113 main(int argc
, char *argv
[]) {
118 int32_t i
, length
, count
, baseOffset
;
119 int result
, ishelp
= 0;
121 U_MAIN_INIT_ARGS(argc
, argv
);
123 pname
= uprv_strchr(*argv
, U_FILE_SEP_CHAR
);
126 pname
= uprv_strchr(*argv
, '/');
135 options
[2].value
= ".";
137 argc
= u_parseArgs(argc
, argv
, sizeof(options
) / sizeof(*options
), options
);
138 ishelp
= options
[0].doesOccur
|| options
[1].doesOccur
;
139 if (ishelp
|| argc
!= 2) {
141 "%csage: %s [ -h, -?, --help ] [ -n ] [ -C, --comment ] [ -d, --destdir destination ] archive\n", ishelp
? 'U' : 'u', pname
);
143 fprintf(stderr
, "\nOptions: -h, -?, --help print this message and exit\n"
144 " -n do not create files\n"
145 " -C, --comment print the comment embedded in the file and exit\n"
146 " -d, --destdir destination create files in destination\n");
149 return ishelp
? 0 : 1;
152 in
=fopen(argv
[1], "rb");
154 fprintf(stderr
, "%s: unable to open input file \"%s\"\n", pname
, argv
[1]);
158 /* read the beginning of the file */
159 length
=(int32_t)fread(buffer
, 1, sizeof(buffer
), in
);
161 fprintf(stderr
, "%s: input file too short\n", pname
);
166 /* check the validity of the file */
167 if(buffer
[2]!=0xda || buffer
[3]!=0x27) {
168 fprintf(stderr
, "%s: not an ICU data file\n", pname
);
173 /* check the platform properties for the file */
174 info
=(UDataInfo
*)(buffer
+4);
175 if(info
->isBigEndian
!=U_IS_BIG_ENDIAN
) {
176 fprintf(stderr
, "%s: the file is in the wrong byte endianness\n", pname
);
180 if(info
->charsetFamily
!=U_CHARSET_FAMILY
) {
181 fprintf(stderr
, "%s: the file is not built for this machine's charset family\n", pname
);
186 /* check that this is a common data file */
187 if(info
->dataFormat
[0]!=0x43 || info
->dataFormat
[1]!=0x6d || info
->dataFormat
[2]!=0x6e || info
->dataFormat
[3]!=0x44) {
188 fprintf(stderr
, "%s: this file is not a common data (archive) file\n", pname
);
193 /* check for version 1 */
194 if(info
->formatVersion
[0]!=1) {
195 fprintf(stderr
, "%s: the format version %d.%d.%d.%d is not known\n", pname
,
196 info
->formatVersion
[0], info
->formatVersion
[1], info
->formatVersion
[2], info
->formatVersion
[3]);
201 /* do we want to show the comment, and is there a comment? */
202 if (options
[4].doesOccur
&& *(uint16_t *)buffer
>4+info
->size
) {
203 printf("%s\n", (const char *)(buffer
+4+info
->size
));
207 /* output all filenames */
208 baseOffset
=*(uint16_t *)buffer
;
209 base
=buffer
+baseOffset
;
212 /* printf("files[%ld]\n", (long)count); */
213 for(i
=0; i
<count
; ++i
) {
214 printf("%s%c%s\n", options
[2].value
, U_FILE_SEP_CHAR
, base
+*p
);
217 /* puts("endfiles"); */
219 if (options
[3].doesOccur
) { /* Do not extract. */
223 /* sort all files by their offsets in the common file */
224 qsort(base
+4, count
, 8, compareFiles
);
226 /* write all files except the last one */
227 p
=(int32_t *)(base
+4);
229 for(i
=0; i
<count
; ++i
) {
230 /* the size is the difference between this file's offset and the next one's */
231 result
=copyFile(in
, baseOffset
+p
[1], p
[3]-p
[1], options
[2].value
, (const char *)(base
+*p
));
239 /* write the last file */
241 /* the size is the number of bytes to the end of the common file */
242 if(0!=fseek(in
, 0, SEEK_END
)) {
243 fprintf(stderr
, "%s: unable to seek to the end of the common file\n", pname
);
246 result
=copyFile(in
, baseOffset
+p
[1], (int32_t)ftell(in
)-baseOffset
-p
[1], options
[2].value
, (const char *)(base
+*p
));
258 * Hey, Emacs, please set the following:
261 * indent-tabs-mode: nil