2 *******************************************************************************
4 * Copyright (C) 2000-2004, 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/putil.h"
27 #include "unicode/udata.h"
31 static uint8_t buffer
[100000], buffer2
[128*1024];
33 static const char *pname
;
35 static UOption options
[]={
37 /*1*/ UOPTION_HELP_QUESTION_MARK
,
38 /*2*/ UOPTION_DESTDIR
,
39 /*3*/ UOPTION_DEF(0, 'n', UOPT_NO_ARG
),
40 /*4*/ UOPTION_DEF("comment", 'C', UOPT_NO_ARG
),
44 compareFiles(const void *file1
, const void *file2
) {
45 /* sort by file offset */
46 int32_t diff
=*((int32_t *)file1
+1)-*((int32_t *)file2
+1);
48 return (int)(diff
>>15)|1;
55 copyFile(FILE *in
, int32_t offset
, int32_t size
, const char *dir
, const char *name
) {
60 if(0!=fseek(in
, offset
, SEEK_SET
)) {
61 fprintf(stderr
, "%s: cannot seek to position %ld for file \"%s\"\n", pname
,
66 uprv_strcpy(path
, dir
);
67 p
= path
+ strlen(path
);
68 if (p
[-1] != U_FILE_SEP_CHAR
) {
69 *p
++ = U_FILE_SEP_CHAR
;
73 out
=fopen(path
, "wb");
75 fprintf(stderr
, "%s: unable to open output file \"%s\"\n", pname
, path
);
79 /* copy the contents into the new, separate file */
80 while(size
>sizeof(buffer2
)) {
81 length
=(int32_t)fread(buffer2
, 1, sizeof(buffer2
), in
);
83 fprintf(stderr
, "%s: read error while copying output file \"%s\"\n", pname
, path
);
87 if(length
!=(int32_t)fwrite(buffer2
, 1, length
, out
)) {
88 fprintf(stderr
, "%s: write error while copying output file \"%s\"\n", pname
, path
);
95 length
=(int32_t)fread(buffer2
, 1, size
, in
);
97 fprintf(stderr
, "%s: read error while copying output file \"%s\"\n", pname
, path
);
101 if(length
!=(int32_t)fwrite(buffer2
, 1, length
, out
)) {
102 fprintf(stderr
, "%s: write error while copying output file \"%s\"\n", pname
, path
);
114 main(int argc
, char *argv
[]) {
119 int32_t i
, length
, count
, baseOffset
;
120 int result
, ishelp
= 0;
122 U_MAIN_INIT_ARGS(argc
, argv
);
124 pname
= uprv_strchr(*argv
, U_FILE_SEP_CHAR
);
127 pname
= uprv_strchr(*argv
, '/');
136 options
[2].value
= ".";
138 argc
= u_parseArgs(argc
, argv
, sizeof(options
) / sizeof(*options
), options
);
139 ishelp
= options
[0].doesOccur
|| options
[1].doesOccur
;
140 if (ishelp
|| argc
!= 2) {
142 "%csage: %s [ -h, -?, --help ] [ -n ] [ -C, --comment ] [ -d, --destdir destination ] archive\n", ishelp
? 'U' : 'u', pname
);
144 fprintf(stderr
, "\nOptions: -h, -?, --help print this message and exit\n"
145 " -n do not create files\n"
146 " -C, --comment print the comment embedded in the file and exit\n"
147 " -d, --destdir destination create files in destination\n");
150 return ishelp
? 0 : 1;
153 in
=fopen(argv
[1], "rb");
155 fprintf(stderr
, "%s: unable to open input file \"%s\"\n", pname
, argv
[1]);
159 /* read the beginning of the file */
160 length
=(int32_t)fread(buffer
, 1, sizeof(buffer
), in
);
162 fprintf(stderr
, "%s: input file too short\n", pname
);
167 /* check the validity of the file */
168 if(buffer
[2]!=0xda || buffer
[3]!=0x27) {
169 fprintf(stderr
, "%s: not an ICU data file\n", pname
);
174 /* check the platform properties for the file */
175 info
=(UDataInfo
*)(buffer
+4);
176 if(info
->isBigEndian
!=U_IS_BIG_ENDIAN
) {
177 fprintf(stderr
, "%s: the file is in the wrong byte endianness\n", pname
);
181 if(info
->charsetFamily
!=U_CHARSET_FAMILY
) {
182 fprintf(stderr
, "%s: the file is not built for this machine's charset family\n", pname
);
187 /* check that this is a common data file */
188 if(info
->dataFormat
[0]!=0x43 || info
->dataFormat
[1]!=0x6d || info
->dataFormat
[2]!=0x6e || info
->dataFormat
[3]!=0x44) {
189 fprintf(stderr
, "%s: this file is not a common data (archive) file\n", pname
);
194 /* check for version 1 */
195 if(info
->formatVersion
[0]!=1) {
196 fprintf(stderr
, "%s: the format version %d.%d.%d.%d is not known\n", pname
,
197 info
->formatVersion
[0], info
->formatVersion
[1], info
->formatVersion
[2], info
->formatVersion
[3]);
202 /* do we want to show the comment, and is there a comment? */
203 if (options
[4].doesOccur
&& *(uint16_t *)buffer
>4+info
->size
) {
204 printf("%s\n", (const char *)(buffer
+4+info
->size
));
208 /* output all filenames */
209 baseOffset
=*(uint16_t *)buffer
;
210 base
=buffer
+baseOffset
;
213 /* printf("files[%ld]\n", (long)count); */
214 for(i
=0; i
<count
; ++i
) {
215 printf("%s%c%s\n", options
[2].value
, U_FILE_SEP_CHAR
, base
+*p
);
218 /* puts("endfiles"); */
220 if (options
[3].doesOccur
) { /* Do not extract. */
224 /* sort all files by their offsets in the common file */
225 qsort(base
+4, count
, 8, compareFiles
);
227 /* write all files except the last one */
228 p
=(int32_t *)(base
+4);
230 for(i
=0; i
<count
; ++i
) {
231 /* the size is the difference between this file's offset and the next one's */
232 result
=copyFile(in
, baseOffset
+p
[1], p
[3]-p
[1], options
[2].value
, (const char *)(base
+*p
));
240 /* write the last file */
242 /* the size is the number of bytes to the end of the common file */
243 if(0!=fseek(in
, 0, SEEK_END
)) {
244 fprintf(stderr
, "%s: unable to seek to the end of the common file\n", pname
);
247 result
=copyFile(in
, baseOffset
+p
[1], (int32_t)ftell(in
)-baseOffset
-p
[1], options
[2].value
, (const char *)(base
+*p
));
259 * Hey, Emacs, please set the following:
262 * indent-tabs-mode: nil