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
PrintStyle(Style & style,int32 i)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
PrintStylesAttribute(BFile & file)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
PrintStxtInfo(BFile & file)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
main(int argc,char ** argv)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