1 /* 2 * Copyright 2014 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "SkCommandLineFlags.h" 9 #include "SkPicture.h" 10 #include "SkPictureData.h" 11 #include "SkStream.h" 12 #include "SkFontDescriptor.h" 13 14 DEFINE_string2(input, i, "", "skp on which to report"); 15 DEFINE_bool2(version, v, true, "version"); 16 DEFINE_bool2(cullRect, c, true, "cullRect"); 17 DEFINE_bool2(flags, f, true, "flags"); 18 DEFINE_bool2(tags, t, true, "tags"); 19 DEFINE_bool2(quiet, q, false, "quiet"); 20 21 // This tool can print simple information about an SKP but its main use 22 // is just to check if an SKP has been truncated during the recording 23 // process. 24 // return codes: 25 static const int kSuccess = 0; 26 static const int kTruncatedFile = 1; 27 static const int kNotAnSKP = 2; 28 static const int kInvalidTag = 3; 29 static const int kMissingInput = 4; 30 static const int kIOError = 5; 31 32 int tool_main(int argc, char** argv); 33 int tool_main(int argc, char** argv) { 34 SkCommandLineFlags::SetUsage("Prints information about an skp file"); 35 SkCommandLineFlags::Parse(argc, argv); 36 37 if (FLAGS_input.count() != 1) { 38 if (!FLAGS_quiet) { 39 SkDebugf("Missing input file\n"); 40 } 41 return kMissingInput; 42 } 43 44 SkFILEStream stream(FLAGS_input[0]); 45 if (!stream.isValid()) { 46 if (!FLAGS_quiet) { 47 SkDebugf("Couldn't open file\n"); 48 } 49 return kIOError; 50 } 51 52 size_t totStreamSize = stream.getLength(); 53 54 SkPictInfo info; 55 if (!SkPicture::InternalOnly_StreamIsSKP(&stream, &info)) { 56 return kNotAnSKP; 57 } 58 59 if (FLAGS_version && !FLAGS_quiet) { 60 SkDebugf("Version: %d\n", info.fVersion); 61 } 62 if (FLAGS_cullRect && !FLAGS_quiet) { 63 SkDebugf("Cull Rect: %f,%f,%f,%f\n", 64 info.fCullRect.fLeft, info.fCullRect.fTop, 65 info.fCullRect.fRight, info.fCullRect.fBottom); 66 } 67 if (FLAGS_flags && !FLAGS_quiet) { 68 SkDebugf("Flags: 0x%x\n", info.fFlags); 69 } 70 71 if (!stream.readBool()) { 72 // If we read true there's a picture playback object flattened 73 // in the file; if false, there isn't a playback, so we're done 74 // reading the file. 75 return kSuccess; 76 } 77 78 for (;;) { 79 uint32_t tag = stream.readU32(); 80 if (SK_PICT_EOF_TAG == tag) { 81 break; 82 } 83 84 uint32_t chunkSize = stream.readU32(); 85 size_t curPos = stream.getPosition(); 86 87 // "move" doesn't error out when seeking beyond the end of file 88 // so we need a preemptive check here. 89 if (curPos+chunkSize > totStreamSize) { 90 if (!FLAGS_quiet) { 91 SkDebugf("truncated file\n"); 92 } 93 return kTruncatedFile; 94 } 95 96 // Not all the tags store the chunk size (in bytes). Three 97 // of them store tag-specific size information (e.g., number of 98 // fonts) instead. This forces us to early exit when those 99 // chunks are encountered. 100 switch (tag) { 101 case SK_PICT_READER_TAG: 102 if (FLAGS_tags && !FLAGS_quiet) { 103 SkDebugf("SK_PICT_READER_TAG %d\n", chunkSize); 104 } 105 break; 106 case SK_PICT_FACTORY_TAG: 107 if (FLAGS_tags && !FLAGS_quiet) { 108 SkDebugf("SK_PICT_FACTORY_TAG %d\n", chunkSize); 109 } 110 break; 111 case SK_PICT_TYPEFACE_TAG: { 112 if (FLAGS_tags && !FLAGS_quiet) { 113 SkDebugf("SK_PICT_TYPEFACE_TAG %d\n", chunkSize); 114 } 115 116 const int count = SkToInt(chunkSize); 117 for (int i = 0; i < count; i++) { 118 SkFontDescriptor desc; 119 if (!SkFontDescriptor::Deserialize(&stream, &desc)) { 120 if (!FLAGS_quiet) { 121 SkDebugf("File corruption in SkFontDescriptor\n"); 122 } 123 return kInvalidTag; 124 } 125 } 126 127 // clear this since we've consumed all the typefaces 128 chunkSize = 0; 129 break; 130 } 131 case SK_PICT_PICTURE_TAG: 132 if (FLAGS_tags && !FLAGS_quiet) { 133 SkDebugf("SK_PICT_PICTURE_TAG %d\n", chunkSize); 134 SkDebugf("Exiting early due to format limitations\n"); 135 } 136 return kSuccess; // TODO: need to store size in bytes 137 break; 138 case SK_PICT_BUFFER_SIZE_TAG: 139 if (FLAGS_tags && !FLAGS_quiet) { 140 SkDebugf("SK_PICT_BUFFER_SIZE_TAG %d\n", chunkSize); 141 } 142 break; 143 default: 144 if (!FLAGS_quiet) { 145 SkDebugf("Unknown tag %d\n", chunkSize); 146 } 147 return kInvalidTag; 148 } 149 150 if (!stream.move(chunkSize)) { 151 if (!FLAGS_quiet) { 152 SkDebugf("seek error\n"); 153 } 154 return kTruncatedFile; 155 } 156 } 157 158 return kSuccess; 159 } 160 161 #if !defined SK_BUILD_FOR_IOS 162 int main(int argc, char * const argv[]) { 163 return tool_main(argc, (char**) argv); 164 } 165 #endif 166