xref: /haiku/src/tools/translation/stxtinfo/stxtinfo.cpp (revision a127b88ecbfab58f64944c98aa47722a18e363b2)
1 /*****************************************************************************/
2 // stxtinfo
3 // Written by Michael Wilber, Haiku Translation Kit Team
4 //
5 // Version:
6 //
7 // stxtinfo is a command line program for displaying text information about
8 // Be styled text (the format that StyledEdit uses).  StyledEdit stores the
9 // styled text information as an attribute of the file and it is this
10 // information that this program is concerned with.  This format is outlined
11 // in TranslatorFormats.h.
12 //
13 // This program prints out information from the "styles" attribute that
14 // StyledEdit uses.  If that information is not available, it attempts
15 // to read the styles information from the contents of the file, assuming
16 // that it is the format that BTranslationUtils::PutStyledText() writes
17 // out.
18 //
19 // The intention of this program is to aid with the development and
20 // debugging of the STXTTranslator.  It may also be useful for debugging /
21 // testing StyledEdit.
22 //
23 // This application and all source files used in its construction, except
24 // where noted, are licensed under the MIT License, and have been written
25 // and are:
26 //
27 // Copyright (c) 2003 Haiku Project
28 //
29 // Permission is hereby granted, free of charge, to any person obtaining a
30 // copy of this software and associated documentation files (the "Software"),
31 // to deal in the Software without restriction, including without limitation
32 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
33 // and/or sell copies of the Software, and to permit persons to whom the
34 // Software is furnished to do so, subject to the following conditions:
35 //
36 // The above copyright notice and this permission notice shall be included
37 // in all copies or substantial portions of the Software.
38 //
39 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
40 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
41 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
42 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
43 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
44 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
45 // DEALINGS IN THE SOFTWARE.
46 /*****************************************************************************/
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <ByteOrder.h>
51 #include <File.h>
52 #include <TranslatorFormats.h>
53 #include <Font.h>
54 	// for B_UNICODE_UTF8
55 #include <fs_attr.h>
56 	// for attr_info
57 
58 #define max(x,y) ((x > y) ? x : y)
59 #define DATA_BUFFER_SIZE 64
60 
61 struct StylesHeader {
62 	uint32 magic;	// 41 6c 69 21
63 	uint32 version;	// 0
64 	int32 count;
65 };
66 
67 struct Style {
68 	int32	offset;
69 	char	family[64];
70 	char	style[64];
71 	float	size;
72 	float	shear;	// typically 90.0
73 	uint16	face;	// typically 0
74 	uint8	red;
75 	uint8	green;
76 	uint8	blue;
77 	uint8	alpha;	// 255 == opaque
78 	uint16	reserved; // 0
79 };
80 
81 void
82 PrintStyle(Style &style, int32 i)
83 {
84 	style.offset = B_BENDIAN_TO_HOST_INT32(style.offset);
85 	style.size = B_BENDIAN_TO_HOST_FLOAT(style.size);
86 	style.shear = B_BENDIAN_TO_HOST_FLOAT(style.shear);
87 	style.face = B_BENDIAN_TO_HOST_INT16(style.face);
88 	style.reserved = B_BENDIAN_TO_HOST_INT16(style.reserved);
89 
90 	printf("\nStyle %d:\n", static_cast<int>(i + 1));
91 	printf("offset: %d\n", static_cast<int>(style.offset));
92 	printf("family: %s\n", style.family);
93 	printf("style: %s\n", style.style);
94 	printf("size: %f\n", style.size);
95 	printf("shear: %f (typically 90.0)\n", style.shear);
96 	printf("face: %u (typically 0)\n",
97 		static_cast<unsigned int>(style.face));
98 	printf("RGBA: (%u, %u, %u, %u)\n",
99 		static_cast<unsigned int>(style.red),
100 		static_cast<unsigned int>(style.blue),
101 		static_cast<unsigned int>(style.green),
102 		static_cast<unsigned int>(style.alpha));
103 		printf("reserved: %u (should be 0)\n",
104 		static_cast<unsigned int>(style.reserved));
105 }
106 
107 bool
108 PrintStylesAttribute(BFile &file)
109 {
110 	const char *kAttrName = "styles";
111 	attr_info info;
112 
113 	if (file.GetAttrInfo(kAttrName, &info) != B_OK)
114 		return false;
115 	if (info.type != B_RAW_TYPE) {
116 		printf("Error: styles attribute is of the wrong type\n");
117 		return false;
118 	}
119 	if (info.size < 160) {
120 		printf("Error: styles attribute is missing information\n");
121 		return false;
122 	}
123 
124 	uint8 *pflatRunArray = new uint8[info.size];
125 	if (!pflatRunArray) {
126 		printf("Error: Not enough memory available to read styles attribute\n");
127 		return false;
128 	}
129 
130 	ssize_t amtread = file.ReadAttr(kAttrName, B_RAW_TYPE, 0,
131 		pflatRunArray, info.size);
132 	if (amtread != info.size) {
133 		printf("Error: Unable to read styles attribute\n");
134 		return false;
135 	}
136 
137 	// Check Styles
138 	StylesHeader stylesheader;
139 	memcpy(&stylesheader, pflatRunArray, sizeof(StylesHeader));
140 	if (swap_data(B_UINT32_TYPE, &stylesheader, sizeof(StylesHeader),
141 		B_SWAP_BENDIAN_TO_HOST) != B_OK) {
142 		printf("Error: Unable to swap byte order of styles header\n");
143 		return false;
144 	}
145 
146 	// Print StylesHeader info
147 	printf("\"styles\" attribute data:\n\n");
148 
149 	printf("magic number: 0x%.8lx ",
150 		static_cast<unsigned long>(stylesheader.magic));
151 	if (stylesheader.magic == 'Ali!')
152 		printf("(valid)\n");
153 	else
154 		printf("(INVALID, should be 0x%.8lx)\n",
155 			static_cast<unsigned long>('Ali!'));
156 
157 	printf("version: 0x%.8lx ",
158 		static_cast<unsigned long>(stylesheader.version));
159 	if (stylesheader.version == 0)
160 		printf("(valid)\n");
161 	else
162 		printf("(INVALID, should be 0x%.8lx)\n", 0UL);
163 
164 	printf("number of styles: %d\n",
165 		static_cast<int>(stylesheader.count));
166 
167 	// Check and Print out each style
168 	Style *pstyle = reinterpret_cast<Style *>(pflatRunArray + sizeof(StylesHeader));
169 	for (int32 i = 0; i < stylesheader.count; i++)
170 		PrintStyle(*(pstyle + i), i);
171 
172 	delete[] pflatRunArray;
173 	pflatRunArray = NULL;
174 
175 	return true;
176 }
177 
178 bool
179 PrintStxtInfo(BFile &file)
180 {
181 	const uint32 kstxtsize = sizeof(TranslatorStyledTextStreamHeader);
182 	const uint32 ktxtsize = sizeof(TranslatorStyledTextTextHeader);
183 	const uint32 kstylsize = sizeof(TranslatorStyledTextStyleHeader);
184 	const uint32 kStyleSize = sizeof(Style);
185 
186 	uint8 buffer[max(max(max(kstxtsize, ktxtsize), kstylsize), kStyleSize)];
187 
188 	// Check STXT Header
189 	status_t nread = 0;
190 	nread = file.Read(buffer, kstxtsize);
191 	if (nread != static_cast<status_t>(kstxtsize)) {
192 		printf("Error: Unable to read stream header\n");
193 		return false;
194 	}
195 	TranslatorStyledTextStreamHeader stxtheader;
196 	memcpy(&stxtheader, buffer, kstxtsize);
197 	if (swap_data(B_UINT32_TYPE, &stxtheader, kstxtsize,
198 		B_SWAP_BENDIAN_TO_HOST) != B_OK) {
199 		printf("Error: Unable to swap byte order of stream header\n");
200 		return false;
201 	}
202 
203 	if (stxtheader.header.magic != B_STYLED_TEXT_FORMAT) {
204 		printf("Styled text magic number is incorrect, aborting.\n");
205 		return false;
206 	}
207 
208 	// Print Stream Header (STXT)
209 	printf("Stream Header (STXT section):\n\n");
210 
211 	printf("magic number: 0x%.8lx ", stxtheader.header.magic);
212 	if (stxtheader.header.magic == B_STYLED_TEXT_FORMAT)
213 		printf("(valid)\n");
214 	else
215 		printf("(INVALID, should be 0x%.8lx)\n",
216 			static_cast<unsigned long>(B_STYLED_TEXT_FORMAT));
217 
218 	printf("header size: %u ",
219 		static_cast<unsigned int>(stxtheader.header.header_size));
220 	if (stxtheader.header.header_size == kstxtsize)
221 		printf("(valid)\n");
222 	else
223 		printf("(INVALID, should be %u)\n",
224 			static_cast<unsigned int>(kstxtsize));
225 
226 	printf("data size: %u ",
227 		static_cast<unsigned int>(stxtheader.header.data_size));
228 	if (stxtheader.header.data_size == 0)
229 		printf("(valid)\n");
230 	else
231 		printf("(INVALID, should be 0)\n");
232 
233 	printf("version: %d ",
234 		static_cast<int>(stxtheader.version));
235 	if (stxtheader.version == 100)
236 		printf("(valid)\n");
237 		else
238 		printf("(INVALID, should be 100)\n");
239 
240 
241 	// Check the TEXT header
242 	TranslatorStyledTextTextHeader txtheader;
243 	if (file.Read(buffer, ktxtsize) != static_cast<ssize_t>(ktxtsize)) {
244 		printf("Error: Unable to read text header\n");
245 		return false;
246 	}
247 	memcpy(&txtheader, buffer, ktxtsize);
248 	if (swap_data(B_UINT32_TYPE, &txtheader, ktxtsize,
249 		B_SWAP_BENDIAN_TO_HOST) != B_OK) {
250 		printf("Error: Unable to swap byte order of text header\n");
251 		return false;
252 	}
253 
254 	// Print Text Header (TEXT)
255 	printf("\nText Header (TEXT section):\n\n");
256 
257 	printf("magic number: 0x%.8lx ", txtheader.header.magic);
258 	if (txtheader.header.magic == 'TEXT')
259 		printf("(valid)\n");
260 	else
261 		printf("(INVALID, should be 0x%.8lx)\n",
262 			static_cast<unsigned long>('TEXT'));
263 
264 	printf("header size: %u ",
265 		static_cast<unsigned int>(txtheader.header.header_size));
266 	if (stxtheader.header.header_size == ktxtsize)
267 		printf("(valid)\n");
268 	else
269 		printf("(INVALID, should be %u)\n",
270 			static_cast<unsigned int>(ktxtsize));
271 
272 	printf("data size (bytes of text): %u\n",
273 		static_cast<unsigned int>(txtheader.header.data_size));
274 
275 	printf("character set: %d ",
276 		static_cast<int>(txtheader.charset));
277 	if (txtheader.charset == B_UNICODE_UTF8)
278 		printf("(valid)\n");
279 	else
280 		printf("(INVALID, should be %d)\n", B_UNICODE_UTF8);
281 
282 	// Skip the text data
283 	off_t seekresult, pos;
284 	pos = stxtheader.header.header_size +
285 		txtheader.header.header_size +
286 		txtheader.header.data_size;
287 	seekresult = file.Seek(txtheader.header.data_size, SEEK_CUR);
288 	if (seekresult < pos) {
289 		printf("Error: Unable to seek past text data. " \
290 			"Text data could be missing\n");
291 		return false;
292 	}
293 	if (seekresult > pos) {
294 		printf("Error: File position is beyond expected value\n");
295 		return false;
296 	}
297 
298 	// Check the STYL header (not all STXT files have this)
299 	ssize_t read = 0;
300 	TranslatorStyledTextStyleHeader stylheader;
301 	read = file.Read(buffer, kstylsize);
302 	if (read != static_cast<ssize_t>(kstylsize) && read != 0) {
303 		printf("Error: Unable to read entire style header\n");
304 		return false;
305 	}
306 
307 	// If there is no STYL header (and no errors)
308 	if (read != static_cast<ssize_t>(kstylsize)) {
309 		printf("\nFile contains no Style Header (STYL section)\n");
310 		return false;
311 	}
312 
313 	memcpy(&stylheader, buffer, kstylsize);
314 	if (swap_data(B_UINT32_TYPE, &stylheader, kstylsize,
315 		B_SWAP_BENDIAN_TO_HOST) != B_OK) {
316 		printf("Error: Unable to swap byte order of style header\n");
317 		return false;
318 	}
319 
320 	// Print Style Header (STYL)
321 	printf("\nStyle Header (STYL section):\n\n");
322 
323 	printf("magic number: 0x%.8lx ", stylheader.header.magic);
324 	if (stylheader.header.magic == 'STYL')
325 		printf("(valid)\n");
326 	else
327 		printf("(INVALID, should be 0x%.8lx)\n",
328 			static_cast<unsigned long>('STYL'));
329 
330 	printf("header size: %u ",
331 		static_cast<unsigned int>(stylheader.header.header_size));
332 	if (stylheader.header.header_size == kstylsize)
333 		printf("(valid)\n");
334 	else
335 		printf("(INVALID, should be %u)\n",
336 			static_cast<unsigned int>(kstylsize));
337 
338 	printf("data size: %u\n",
339 		static_cast<unsigned int>(stylheader.header.data_size));
340 	printf("apply offset: %u (usually 0)\n",
341 		static_cast<unsigned int>(stylheader.apply_offset));
342 	printf("apply length: %u (usually the text data size)\n",
343 		static_cast<unsigned int>(stylheader.apply_length));
344 
345 	// Check Styles
346 	StylesHeader stylesheader;
347 	read = file.Read(buffer, sizeof(StylesHeader));
348 	if (read != sizeof(StylesHeader)) {
349 		printf("Error: Unable to read Styles header\n");
350 		return false;
351 	}
352 	memcpy(&stylesheader, buffer, sizeof(StylesHeader));
353 	if (swap_data(B_UINT32_TYPE, &stylesheader, sizeof(StylesHeader),
354 		B_SWAP_BENDIAN_TO_HOST) != B_OK) {
355 		printf("Error: Unable to swap byte order of styles header\n");
356 		return false;
357 	}
358 
359 	// Print StylesHeader info
360 	printf("\nStyles Header (Ali! section):\n\n");
361 
362 	printf("magic number: 0x%.8lx ",
363 		static_cast<unsigned long>(stylesheader.magic));
364 	if (stylesheader.magic == 'Ali!')
365 		printf("(valid)\n");
366 	else
367 		printf("(INVALID, should be 0x%.8lx)\n",
368 			static_cast<unsigned long>('Ali!'));
369 
370 	printf("version: 0x%.8lx ",
371 		static_cast<unsigned long>(stylesheader.version));
372 	if (stylesheader.version == 0)
373 		printf("(valid)\n");
374 	else
375 		printf("(INVALID, should be 0x%.8lx)\n", 0UL);
376 
377 	printf("number of styles: %d\n",
378 		static_cast<int>(stylesheader.count));
379 
380 	// Check and Print out each style
381 	for (int32 i = 0; i < stylesheader.count; i++) {
382 		Style style;
383 		read = file.Read(&style, sizeof(Style));
384 		if (read != sizeof(Style)) {
385 			printf("Error: Unable to read style %d\n",
386 				static_cast<int>(i + 1));
387 			return false;
388 		}
389 
390 		PrintStyle(style, i);
391 	}
392 
393 	return true;
394 }
395 
396 int
397 main(int argc, char **argv)
398 {
399 	printf("\n");
400 
401 	if (argc == 2) {
402 		BFile file(argv[1], B_READ_ONLY);
403 		if (file.InitCheck() != B_OK)
404 			printf("Error opening %s\n", argv[1]);
405 		else {
406 			printf("Be styled text information for: %s\n\n", argv[1]);
407 			if (PrintStylesAttribute(file) == false) {
408 				printf("Unable to read styles attribute, attempting to read " \
409 					"style information from file...\n\n");
410 				PrintStxtInfo(file);
411 			}
412 		}
413 	}
414 	else {
415 		printf("stxtinfo - reports information about a Be styled text file\n");
416 		printf("\nUsage:\n");
417 		printf("stxtinfo filename.stxt\n");
418 	}
419 
420 	printf("\n");
421 
422 	return 0;
423 }
424 
425