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