skpinfo.cpp 5.0 KB

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