Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(88)

Side by Side Diff: chrome/tools/mac_helpers/infoplist_strings_util.mm

Issue 171040: add the InfoPlist.strings generation based on GRD strings.... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 11 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/tools/build/apply_locales.py ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Property Changes:
Name: svn:eol-style
+ LF
OLDNEW
(Empty)
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // Helper tool that is built and run during a build to pull strings from
6 // the GRD files and generate the InfoPlist.strings files needed for
7 // Mac OS X app bundles.
8
9 #import <Foundation/Foundation.h>
10
11 #include <stdio.h>
12 #include <unistd.h>
13
14 #include "base/data_pack.h"
15 #include "base/file_path.h"
16 #include "base/scoped_nsautorelease_pool.h"
17 #include "base/scoped_ptr.h"
18 #include "base/string_piece.h"
19 #include "base/string_util.h"
20 #include "grit/chromium_strings.h"
21
22 namespace {
23
24 NSString* ApplicationVersionString(const char* version_file_path) {
25 NSError* error = nil;
26 NSString* path_string = [NSString stringWithUTF8String:version_file_path];
27 NSString* version_file =
28 [NSString stringWithContentsOfFile:path_string
29 encoding:NSUTF8StringEncoding
30 error:&error];
31 if (!version_file || error) {
32 fprintf(stderr, "Failed to load version file: %s\n",
33 [[error description] UTF8String]);
34 return nil;
35 }
36
37 int major = 0, minor = 0, build = 0, patch = 0;
38 NSScanner* scanner = [NSScanner scannerWithString:version_file];
39 if ([scanner scanString:@"MAJOR=" intoString:nil] &&
40 [scanner scanInt:&major] &&
41 [scanner scanString:@"MINOR=" intoString:nil] &&
42 [scanner scanInt:&minor] &&
43 [scanner scanString:@"BUILD=" intoString:nil] &&
44 [scanner scanInt:&build] &&
45 [scanner scanString:@"PATCH=" intoString:nil] &&
46 [scanner scanInt:&patch]) {
47 return [NSString stringWithFormat:@"%d.%d.%d.%d",
48 major, minor, build, patch];
49 }
50 fprintf(stderr, "Failed to parse version file\n");
51 return nil;
52 }
53
54 base::DataPack* LoadResourceDataPack(const char* dir_path,
55 const char* branding_strings_name,
56 const char* locale_name) {
57 base::DataPack* resource_pack = NULL;
58
59 NSString* resource_path = [NSString stringWithFormat:@"%s/%s_%s.pak",
60 dir_path, branding_strings_name, locale_name];
61 if (resource_path) {
62 FilePath resources_pak_path([resource_path fileSystemRepresentation]);
63 resource_pack = new base::DataPack;
64 bool success = resource_pack->Load(resources_pak_path);
65 if (!success) {
66 delete resource_pack;
67 resource_pack = NULL;
68 }
69 }
70
71 return resource_pack;
72 }
73
74 NSString* LoadStringFromDataPack(base::DataPack* data_pack,
75 const char* data_pack_lang,
76 uint32_t resource_id,
77 const char* resource_id_str) {
78 NSString* result = nil;
79 StringPiece data;
80 if (data_pack->Get(resource_id, &data)) {
81 // Data pack encodes strings as UTF16.
82 result =
83 [[[NSString alloc] initWithBytes:data.data()
84 length:data.length()
85 encoding:NSUTF16LittleEndianStringEncoding]
86 autorelease];
87 }
88 if (!result) {
89 fprintf(stderr, "ERROR: failed to load string %s for lang %s\n",
90 resource_id_str, data_pack_lang);
91 exit(1);
92 }
93 return result;
94 }
95
96 // Escape quotes, newlines, etc so there are no errors when the strings file
97 // is parsed.
98 NSString* EscapeForStringsFileValue(NSString* str) {
99 NSMutableString* worker = [NSMutableString stringWithString:str];
100
101 // Since this is a build tool, we don't really worry about making this
102 // the most efficient code.
103
104 // Backslash first since we need to do it before we put in all the others
105 [worker replaceOccurrencesOfString:@"\\"
106 withString:@"\\\\"
107 options:NSLiteralSearch
108 range:NSMakeRange(0, [worker length])];
109 // Now the rest of them.
110 [worker replaceOccurrencesOfString:@"\n"
111 withString:@"\\n"
112 options:NSLiteralSearch
113 range:NSMakeRange(0, [worker length])];
114 [worker replaceOccurrencesOfString:@"\r"
115 withString:@"\\r"
116 options:NSLiteralSearch
117 range:NSMakeRange(0, [worker length])];
118 [worker replaceOccurrencesOfString:@"\t"
119 withString:@"\\t"
120 options:NSLiteralSearch
121 range:NSMakeRange(0, [worker length])];
122 [worker replaceOccurrencesOfString:@"\""
123 withString:@"\\\""
124 options:NSLiteralSearch
125 range:NSMakeRange(0, [worker length])];
126
127 return [[worker copy] autorelease];
128 }
129
130 // The valid types for the -t arg
131 const char* kAppType_Main = "main"; // Main app
132 const char* kAppType_Helper = "helper"; // Helper app
133
134 } // namespace
135
136 int main(int argc, char* const argv[]) {
137 base::ScopedNSAutoreleasePool autorelease_pool;
138
139 const char* version_file_path = NULL;
140 const char* grit_output_dir = NULL;
141 const char* branding_strings_name = NULL;
142 const char* output_dir = NULL;
143 const char* app_type = kAppType_Main;
144
145 // Process the args
146 int ch;
147 while ((ch = getopt(argc, argv, "t:v:g:b:o:")) != -1) {
148 switch (ch) {
149 case 't':
150 app_type = optarg;
151 break;
152 case 'v':
153 version_file_path = optarg;
154 break;
155 case 'g':
156 grit_output_dir = optarg;
157 break;
158 case 'b':
159 branding_strings_name = optarg;
160 break;
161 case 'o':
162 output_dir = optarg;
163 break;
164 default:
165 fprintf(stderr, "ERROR: bad command line arg\n");
166 exit(1);
167 break;
168 }
169 }
170 argc -= optind;
171 argv += optind;
172
173 #define CHECK_ARG(a, b) \
174 do { \
175 if ((a)) { \
176 fprintf(stderr, "ERROR: " b "\n"); \
177 exit(1); \
178 } \
179 } while (false)
180
181 // Check our args
182 CHECK_ARG(!version_file_path, "Missing VERSION file path");
183 CHECK_ARG(!grit_output_dir, "Missing grit output dir path");
184 CHECK_ARG(!output_dir, "Missing path to write InfoPlist.strings files");
185 CHECK_ARG(!branding_strings_name, "Missing branding strings file name");
186 CHECK_ARG(argc == 0, "Missing language list");
187 CHECK_ARG((strcmp(app_type, kAppType_Main) != 0 &&
188 strcmp(app_type, kAppType_Helper) != 0),
189 "Unknown app type");
190
191 char* const* lang_list = argv;
192 int lang_list_count = argc;
193
194 // Parse the version file and build our string
195 NSString* version_string = ApplicationVersionString(version_file_path);
196 if (!version_string) {
197 fprintf(stderr, "ERROR: failed to get a version string");
198 exit(1);
199 }
200
201 NSFileManager* fm = [NSFileManager defaultManager];
202
203 for (int loop = 0; loop < lang_list_count; ++loop) {
204 const char* cur_lang = lang_list[loop];
205
206 // Open the branded string pak file
207 scoped_ptr<base::DataPack> branded_data_pack(
208 LoadResourceDataPack(grit_output_dir,
209 branding_strings_name,
210 cur_lang));
211 if (branded_data_pack.get() == NULL) {
212 fprintf(stderr, "ERROR: Failed to load branded pak for language: %s\n",
213 cur_lang);
214 exit(1);
215 }
216
217 uint32_t name_id = IDS_PRODUCT_NAME;
218 const char* name_id_str = "IDS_PRODUCT_NAME";
219 uint32_t short_name_id = IDS_SHORT_PRODUCT_NAME;
220 const char* short_name_id_str = "IDS_SHORT_PRODUCT_NAME";
221 if (strcmp(app_type, kAppType_Helper) == 0) {
222 name_id = IDS_HELPER_NAME;
223 name_id_str = "IDS_HELPER_NAME";
224 short_name_id = IDS_SHORT_HELPER_NAME;
225 short_name_id_str = "IDS_SHORT_HELPER_NAME";
226 }
227
228 // Fetch the strings
229 NSString* name =
230 LoadStringFromDataPack(branded_data_pack.get(), cur_lang,
231 name_id, name_id_str);
232 NSString* short_name =
233 LoadStringFromDataPack(branded_data_pack.get(), cur_lang,
234 short_name_id, short_name_id_str);
235 NSString* copyright =
236 LoadStringFromDataPack(branded_data_pack.get(), cur_lang,
237 IDS_ABOUT_VERSION_COPYRIGHT,
238 "IDS_ABOUT_VERSION_COPYRIGHT");
239
240 // For now, assume this is ok for all languages. If we need to, this could
241 // be moved into generated_resources.grd and fetched.
242 NSString *get_info = [NSString stringWithFormat:@"%@ %@, %@",
243 name, version_string, copyright];
244
245 // Generate the InfoPlist.strings file contents
246 NSString* strings_file_contents_string =
247 [NSString stringWithFormat:
248 @"CFBundleDisplayName = \"%@\";\n"
249 @"CFBundleGetInfoString = \"%@\";\n"
250 @"CFBundleName = \"%@\";\n"
251 @"NSHumanReadableCopyright = \"%@\";\n",
252 EscapeForStringsFileValue(name),
253 EscapeForStringsFileValue(get_info),
254 EscapeForStringsFileValue(short_name),
255 EscapeForStringsFileValue(copyright)];
256
257 // We set up Xcode projects expecting strings files to be UTF8, so make
258 // sure we write the data in that form. When Xcode copies them it will
259 // put them final runtime encoding.
260 NSData* strings_file_contents_utf8 =
261 [strings_file_contents_string dataUsingEncoding:NSUTF8StringEncoding];
262
263 if ([strings_file_contents_utf8 length] == 0) {
264 fprintf(stderr, "ERROR: failed to get the utf8 encoding of the strings "
265 "file for language: %s\n", cur_lang);
266 exit(1);
267 }
268
269 // Make sure the lproj we write to exists
270 NSString *output_path =
271 [[NSString stringWithUTF8String:output_dir]
272 stringByAppendingPathComponent:
273 [NSString stringWithFormat:@"%s.lproj", cur_lang]];
274 NSError* error = nil;
275 if (![fm fileExistsAtPath:output_path] &&
276 ![fm createDirectoryAtPath:output_path
277 withIntermediateDirectories:YES
278 attributes:nil
279 error:&error]) {
280 fprintf(stderr, "ERROR: '%s' didn't exist or we failed to create it\n",
281 [output_path UTF8String]);
282 exit(1);
283 }
284
285 // Write out the file
286 output_path =
287 [output_path stringByAppendingPathComponent:@"InfoPlist.strings"];
288 if (![strings_file_contents_utf8 writeToFile:output_path
289 atomically:YES]) {
290 fprintf(stderr, "ERROR: Failed to write out '%s'\n",
291 [output_path UTF8String]);
292 exit(1);
293 }
294 }
295 return 0;
296 }
OLDNEW
« no previous file with comments | « chrome/tools/build/apply_locales.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698