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