]> git.saurik.com Git - apple/icu.git/blob - icuSources/tools/gencmn/decmn.c
ICU-6.2.10.tar.gz
[apple/icu.git] / icuSources / tools / gencmn / decmn.c
1 /*
2 *******************************************************************************
3 *
4 * Copyright (C) 2000-2004, International Business Machines
5 * Corporation and others. All Rights Reserved.
6 *
7 *******************************************************************************
8 * file name: decmn.c
9 * encoding: US-ASCII
10 * tab size: 8 (not used)
11 * indentation:4
12 *
13 * created on: 2001mar05
14 * created by: Markus W. Scherer
15 * changes by: Yves Arrouye
16 *
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.
21 */
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include "unicode/utypes.h"
26 #include "unicode/putil.h"
27 #include "unicode/udata.h"
28 #include "uoptions.h"
29 #include "cstring.h"
30
31 static uint8_t buffer[100000], buffer2[128*1024];
32
33 static const char *pname;
34
35 static UOption options[]={
36 /*0*/ UOPTION_HELP_H,
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),
41 };
42
43 static int
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);
47 if(diff!=0) {
48 return (int)(diff>>15)|1;
49 } else {
50 return 0;
51 }
52 }
53
54 static int
55 copyFile(FILE *in, int32_t offset, int32_t size, const char *dir, const char *name) {
56 FILE *out;
57 int32_t length;
58 char path[512], *p;
59
60 if(0!=fseek(in, offset, SEEK_SET)) {
61 fprintf(stderr, "%s: cannot seek to position %ld for file \"%s\"\n", pname,
62 (long)offset, name);
63 return 4;
64 }
65
66 uprv_strcpy(path, dir);
67 p = path + strlen(path);
68 if (p[-1] != U_FILE_SEP_CHAR) {
69 *p++ = U_FILE_SEP_CHAR;
70 }
71 uprv_strcpy(p, name);
72
73 out=fopen(path, "wb");
74 if(out==NULL) {
75 fprintf(stderr, "%s: unable to open output file \"%s\"\n", pname, path);
76 return 5;
77 }
78
79 /* copy the contents into the new, separate file */
80 while(size>sizeof(buffer2)) {
81 length=(int32_t)fread(buffer2, 1, sizeof(buffer2), in);
82 if(length<=0) {
83 fprintf(stderr, "%s: read error while copying output file \"%s\"\n", pname, path);
84 fclose(out);
85 return 4;
86 }
87 if(length!=(int32_t)fwrite(buffer2, 1, length, out)) {
88 fprintf(stderr, "%s: write error while copying output file \"%s\"\n", pname, path);
89 fclose(out);
90 return 5;
91 }
92 size-=length;
93 }
94 while(size>0) {
95 length=(int32_t)fread(buffer2, 1, size, in);
96 if(length<=0) {
97 fprintf(stderr, "%s: read error while copying output file \"%s\"\n", pname, path);
98 fclose(out);
99 return 4;
100 }
101 if(length!=(int32_t)fwrite(buffer2, 1, length, out)) {
102 fprintf(stderr, "%s: write error while copying output file \"%s\"\n", pname, path);
103 fclose(out);
104 return 5;
105 }
106 size-=length;
107 }
108
109 fclose(out);
110 return 0;
111 }
112
113 extern int
114 main(int argc, char *argv[]) {
115 FILE *in;
116 UDataInfo *info;
117 uint8_t *base;
118 int32_t *p;
119 int32_t i, length, count, baseOffset;
120 int result, ishelp = 0;
121
122 U_MAIN_INIT_ARGS(argc, argv);
123
124 pname = uprv_strchr(*argv, U_FILE_SEP_CHAR);
125 #ifdef WIN32
126 if (!pname) {
127 pname = uprv_strchr(*argv, '/');
128 }
129 #endif
130 if (pname) {
131 ++pname;
132 } else {
133 pname = argv[0];
134 }
135
136 options[2].value = ".";
137
138 argc = u_parseArgs(argc, argv, sizeof(options) / sizeof(*options), options);
139 ishelp = options[0].doesOccur || options[1].doesOccur;
140 if (ishelp || argc != 2) {
141 fprintf(stderr,
142 "%csage: %s [ -h, -?, --help ] [ -n ] [ -C, --comment ] [ -d, --destdir destination ] archive\n", ishelp ? 'U' : 'u', pname);
143 if (ishelp) {
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");
148 }
149
150 return ishelp ? 0 : 1;
151 }
152
153 in=fopen(argv[1], "rb");
154 if(in==NULL) {
155 fprintf(stderr, "%s: unable to open input file \"%s\"\n", pname, argv[1]);
156 return 2;
157 }
158
159 /* read the beginning of the file */
160 length=(int32_t)fread(buffer, 1, sizeof(buffer), in);
161 if(length<20) {
162 fprintf(stderr, "%s: input file too short\n", pname);
163 fclose(in);
164 return 3;
165 }
166
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);
170 fclose(in);
171 return 3;
172 }
173
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);
178 fclose(in);
179 return 3;
180 }
181 if(info->charsetFamily!=U_CHARSET_FAMILY) {
182 fprintf(stderr, "%s: the file is not built for this machine's charset family\n", pname);
183 fclose(in);
184 return 3;
185 }
186
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);
190 fclose(in);
191 return 3;
192 }
193
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]);
198 fclose(in);
199 return 3;
200 }
201
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));
205 return 0;
206 }
207
208 /* output all filenames */
209 baseOffset=*(uint16_t *)buffer;
210 base=buffer+baseOffset;
211 p=(int32_t *)base;
212 count=*p++;
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);
216 p+=2;
217 }
218 /* puts("endfiles"); */
219
220 if (options[3].doesOccur) { /* Do not extract. */
221 return 0;
222 }
223
224 /* sort all files by their offsets in the common file */
225 qsort(base+4, count, 8, compareFiles);
226
227 /* write all files except the last one */
228 p=(int32_t *)(base+4);
229 --count;
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));
233 if(result!=0) {
234 fclose(in);
235 return result;
236 }
237 p+=2;
238 }
239
240 /* write the last file */
241 if(count>=0) {
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);
245 return 4;
246 }
247 result=copyFile(in, baseOffset+p[1], (int32_t)ftell(in)-baseOffset-p[1], options[2].value, (const char *)(base+*p));
248 if(result!=0) {
249 fclose(in);
250 return result;
251 }
252 }
253
254 fclose(in);
255 return 0;
256 }
257
258 /*
259 * Hey, Emacs, please set the following:
260 *
261 * Local Variables:
262 * indent-tabs-mode: nil
263 * End:
264 *
265 */