18a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/*
2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2014 Google Inc.
38a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com *
4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be
5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file.
68a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com */
78a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
88a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkCommandLineFlags.h"
98a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkPicture.h"
108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkPictureData.h"
118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkPictureCommon.h"
128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkStream.h"
138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkFontDescriptor.h"
14fab44db294846ff05d837b9cf0bf97a073891da7bungeman@google.com
15ef3fcd877aa78c1d0ac802043cd8785180304c12bsalomonDEFINE_string2(input, i, "", "skp on which to report");
168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comDEFINE_bool2(version, v, true, "version");
1795cc012ccaea20f372893ae277ea0a8a6339d094mtkleinDEFINE_bool2(cullRect, c, true, "cullRect");
1895cc012ccaea20f372893ae277ea0a8a6339d094mtkleinDEFINE_bool2(flags, f, true, "flags");
1995cc012ccaea20f372893ae277ea0a8a6339d094mtkleinDEFINE_bool2(tags, t, true, "tags");
2095cc012ccaea20f372893ae277ea0a8a6339d094mtkleinDEFINE_bool2(quiet, q, false, "quiet");
2195cc012ccaea20f372893ae277ea0a8a6339d094mtklein
2295cc012ccaea20f372893ae277ea0a8a6339d094mtklein// This tool can print simple information about an SKP but its main use
238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// is just to check if an SKP has been truncated during the recording
248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// process.
258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// return codes:
269aa8b32233702b19b97bebdc2c702e0c53407d45reed@android.comstatic const int kSuccess = 0;
279aa8b32233702b19b97bebdc2c702e0c53407d45reed@android.comstatic const int kTruncatedFile = 1;
289aa8b32233702b19b97bebdc2c702e0c53407d45reed@android.comstatic const int kNotAnSKP = 2;
299aa8b32233702b19b97bebdc2c702e0c53407d45reed@android.comstatic const int kInvalidTag = 3;
309aa8b32233702b19b97bebdc2c702e0c53407d45reed@android.comstatic const int kMissingInput = 4;
319aa8b32233702b19b97bebdc2c702e0c53407d45reed@android.comstatic const int kIOError = 5;
328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comint main(int argc, char** argv) {
348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkCommandLineFlags::SetUsage("Prints information about an skp file");
358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkCommandLineFlags::Parse(argc, argv);
368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (FLAGS_input.count() != 1) {
388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (!FLAGS_quiet) {
39de916c8ac866378cee9af2bf161c79f528d9ccd5reed@google.com            SkDebugf("Missing input file\n");
408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return kMissingInput;
428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
44de916c8ac866378cee9af2bf161c79f528d9ccd5reed@google.com    SkFILEStream stream(FLAGS_input[0]);
458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (!stream.isValid()) {
468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (!FLAGS_quiet) {
478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkDebugf("Couldn't open file\n");
488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return kIOError;
508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
52519f9677a41239808f41a7c13ef1f6e05eb1ed50mtklein@google.com    size_t totStreamSize = stream.getLength();
538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkPictInfo info;
557ffb1b21abcc7bbed5a0fc711f6dd7b9dbb4f577ctguil@chromium.org    if (!SkPicture_StreamIsSKP(&stream, &info)) {
568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return kNotAnSKP;
578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
58de916c8ac866378cee9af2bf161c79f528d9ccd5reed@google.com
598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (FLAGS_version && !FLAGS_quiet) {
608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkDebugf("Version: %d\n", info.getVersion());
618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
62de916c8ac866378cee9af2bf161c79f528d9ccd5reed@google.com    if (FLAGS_cullRect && !FLAGS_quiet) {
638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkDebugf("Cull Rect: %f,%f,%f,%f\n",
648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                 info.fCullRect.fLeft, info.fCullRect.fTop,
65de916c8ac866378cee9af2bf161c79f528d9ccd5reed@google.com                 info.fCullRect.fRight, info.fCullRect.fBottom);
668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
67519f9677a41239808f41a7c13ef1f6e05eb1ed50mtklein@google.com
68519f9677a41239808f41a7c13ef1f6e05eb1ed50mtklein@google.com    if (!stream.readBool()) {
69519f9677a41239808f41a7c13ef1f6e05eb1ed50mtklein@google.com        // If we read true there's a picture playback object flattened
70519f9677a41239808f41a7c13ef1f6e05eb1ed50mtklein@google.com        // in the file; if false, there isn't a playback, so we're done
71519f9677a41239808f41a7c13ef1f6e05eb1ed50mtklein@google.com        // reading the file.
72519f9677a41239808f41a7c13ef1f6e05eb1ed50mtklein@google.com        return kSuccess;
73519f9677a41239808f41a7c13ef1f6e05eb1ed50mtklein@google.com    }
74519f9677a41239808f41a7c13ef1f6e05eb1ed50mtklein@google.com
754516f4786f5dda1b86a8f825b9e8e910d9c2363creed@android.com    for (;;) {
764516f4786f5dda1b86a8f825b9e8e910d9c2363creed@android.com        uint32_t tag = stream.readU32();
774516f4786f5dda1b86a8f825b9e8e910d9c2363creed@android.com        if (SK_PICT_EOF_TAG == tag) {
784516f4786f5dda1b86a8f825b9e8e910d9c2363creed@android.com            break;
794516f4786f5dda1b86a8f825b9e8e910d9c2363creed@android.com        }
80bdf736133b513bb13f7c66e01c8c37ac526ce8d4reed@google.com
81bdf736133b513bb13f7c66e01c8c37ac526ce8d4reed@google.com        uint32_t chunkSize = stream.readU32();
8236352bf5e38f45a70ee4f4fc132a38048d38206dmtklein        size_t curPos = stream.getPosition();
83bdf736133b513bb13f7c66e01c8c37ac526ce8d4reed@google.com
84bdf736133b513bb13f7c66e01c8c37ac526ce8d4reed@google.com        // "move" doesn't error out when seeking beyond the end of file
85bdf736133b513bb13f7c66e01c8c37ac526ce8d4reed@google.com        // so we need a preemptive check here.
86bdf736133b513bb13f7c66e01c8c37ac526ce8d4reed@google.com        if (curPos+chunkSize > totStreamSize) {
87bdf736133b513bb13f7c66e01c8c37ac526ce8d4reed@google.com            if (!FLAGS_quiet) {
88bdf736133b513bb13f7c66e01c8c37ac526ce8d4reed@google.com                SkDebugf("truncated file\n");
89bdf736133b513bb13f7c66e01c8c37ac526ce8d4reed@google.com            }
90bdf736133b513bb13f7c66e01c8c37ac526ce8d4reed@google.com            return kTruncatedFile;
91bdf736133b513bb13f7c66e01c8c37ac526ce8d4reed@google.com        }
92bdf736133b513bb13f7c66e01c8c37ac526ce8d4reed@google.com
93bdf736133b513bb13f7c66e01c8c37ac526ce8d4reed@google.com        // Not all the tags store the chunk size (in bytes). Three
94bdf736133b513bb13f7c66e01c8c37ac526ce8d4reed@google.com        // of them store tag-specific size information (e.g., number of
958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        // fonts) instead. This forces us to early exit when those
968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        // chunks are encountered.
978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        switch (tag) {
988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        case SK_PICT_READER_TAG:
99c4ade57cd4ce5083e0fac19111a6ee6e32e18df4george            if (FLAGS_tags && !FLAGS_quiet) {
1008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                SkDebugf("SK_PICT_READER_TAG %d\n", chunkSize);
1018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
1028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            break;
10345d1d1d9a71253e0ed28ba87f5f946b5845f1d6dcommit-bot@chromium.org        case SK_PICT_FACTORY_TAG:
1040c00f21fee3f5cfa3aa7e5d46ff94cb8cf340451tomhudson@google.com            if (FLAGS_tags && !FLAGS_quiet) {
1058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                SkDebugf("SK_PICT_FACTORY_TAG %d\n", chunkSize);
1068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
1078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            break;
1088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        case SK_PICT_TYPEFACE_TAG: {
1098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (FLAGS_tags && !FLAGS_quiet) {
1108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                SkDebugf("SK_PICT_TYPEFACE_TAG %d\n", chunkSize);
1118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
1128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1130c00f21fee3f5cfa3aa7e5d46ff94cb8cf340451tomhudson@google.com            const int count = SkToInt(chunkSize);
1148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            for (int i = 0; i < count; i++) {
1158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                SkFontDescriptor desc;
1168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                if (!SkFontDescriptor::Deserialize(&stream, &desc)) {
1178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    if (!FLAGS_quiet) {
1188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                        SkDebugf("File corruption in SkFontDescriptor\n");
1198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    }
1208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    return kInvalidTag;
1218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                }
1228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
12345d1d1d9a71253e0ed28ba87f5f946b5845f1d6dcommit-bot@chromium.org
12488cb22b6b4816c7a9ca6c5b795965b4606f9eb7bcommit-bot@chromium.org            // clear this since we've consumed all the typefaces
125b59161f0000eb4aca3dcef29f27ffd0fb5a568e5mtklein            chunkSize = 0;
126b59161f0000eb4aca3dcef29f27ffd0fb5a568e5mtklein            break;
127b59161f0000eb4aca3dcef29f27ffd0fb5a568e5mtklein        }
128b59161f0000eb4aca3dcef29f27ffd0fb5a568e5mtklein        case SK_PICT_PICTURE_TAG:
129b59161f0000eb4aca3dcef29f27ffd0fb5a568e5mtklein            if (FLAGS_tags && !FLAGS_quiet) {
13076f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com                SkDebugf("SK_PICT_PICTURE_TAG %d\n", chunkSize);
13176f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com                SkDebugf("Exiting early due to format limitations\n");
13276f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com            }
13376f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com            return kSuccess;       // TODO: need to store size in bytes
1340f10f7bf1fb43ca6346dc220a076773b1f19a367commit-bot@chromium.org            break;
1350f10f7bf1fb43ca6346dc220a076773b1f19a367commit-bot@chromium.org        case SK_PICT_BUFFER_SIZE_TAG:
1360f10f7bf1fb43ca6346dc220a076773b1f19a367commit-bot@chromium.org            if (FLAGS_tags && !FLAGS_quiet) {
137bc3d92a7d84b56eb235d6c2d9b7de00625200713skia.committer@gmail.com                SkDebugf("SK_PICT_BUFFER_SIZE_TAG %d\n", chunkSize);
138bc3d92a7d84b56eb235d6c2d9b7de00625200713skia.committer@gmail.com            }
1390f10f7bf1fb43ca6346dc220a076773b1f19a367commit-bot@chromium.org            break;
1400f10f7bf1fb43ca6346dc220a076773b1f19a367commit-bot@chromium.org        default:
1410f10f7bf1fb43ca6346dc220a076773b1f19a367commit-bot@chromium.org            if (!FLAGS_quiet) {
1420f10f7bf1fb43ca6346dc220a076773b1f19a367commit-bot@chromium.org                SkDebugf("Unknown tag %d\n", chunkSize);
1430f10f7bf1fb43ca6346dc220a076773b1f19a367commit-bot@chromium.org            }
1440f10f7bf1fb43ca6346dc220a076773b1f19a367commit-bot@chromium.org            return kInvalidTag;
1450f10f7bf1fb43ca6346dc220a076773b1f19a367commit-bot@chromium.org        }
1460f10f7bf1fb43ca6346dc220a076773b1f19a367commit-bot@chromium.org
14736352bf5e38f45a70ee4f4fc132a38048d38206dmtklein        if (!stream.move(chunkSize)) {
14876f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com            if (!FLAGS_quiet) {
14976f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com                SkDebugf("seek error\n");
15028be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org            }
15128be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org            return kTruncatedFile;
15228be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org        }
15328be72b63e457c680c192a34fb9f58e1c693363fvandebo@chromium.org    }
154562b2e67a29f24db4c258aa2fa59cd7b4ee15174bungeman@google.com
155562b2e67a29f24db4c258aa2fa59cd7b4ee15174bungeman@google.com    return kSuccess;
1569c28fa5579734129f1bad026b8b6aea3bf76da5fbungeman@google.com}
1579c28fa5579734129f1bad026b8b6aea3bf76da5fbungeman@google.com