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