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