1 // =================================================================================================
2 // Copyright 2008 Adobe Systems Incorporated
3 // All Rights Reserved.
4 //
5 // NOTICE:  Adobe permits you to use, modify, and distribute this file in accordance with the terms
6 // of the Adobe license agreement accompanying it.
7 //
8 // =================================================================================================
9 
10 #ifndef TagTree_H
11 #define TagTree_H
12 
13 #include <map>
14 #include <list>
15 #include <string>
16 
17 #include "source/EndianUtils.hpp"
18 #include "public/include/XMP_Const.h" //needed for setKV convenience functions
19 
20 #include "samples/source/common/globals.h"
21 #include "samples/source/common/Log.h"
22 #include "samples/source/common/LargeFileAccess.hpp"
23 void LFA_Throw ( const char* msg, int id );
24 
25 using namespace std;
26 
27 // TagTree routines must be able to throw these..
28 class DumpFileException : public std::runtime_error {
29 	public:
30 		DumpFileException(const char* format, ...);
31 
32 		const char* what_dumpfile_reason(); //no override, but almost..
33 	private:
34 		static const unsigned int DUMPFILE_MAX_ERROR_LENGTH=2048;
35 		char buffer [DUMPFILE_MAX_ERROR_LENGTH+1];
36 };
37 
38 class TagTree {
39 private:
40 	struct Node; //forward-looking declaration
41 	typedef std::list<Node> NodeList;
42 	typedef std::list<Node>::iterator NodeListIter;
43 
44 	struct Node {
45 		std::string key;		// node structure name resp. tag name
46 		std::string value;		// value if applicable/of relevance
47 		std::string comment;	// comment string, add-on as many as you like
48 		NodeList children;		// children of this tag, if any
49 	public:
50 		//default-constructor is an std::container requirement. DO NOT ACTUALLY USE.
NodeNode51 		Node() {
52 			key=std::string("unnamed"); // should be overridden at all times
53 			value=std::string("no value");
54 			comment=std::string("no comment");
55 			children.clear();			// be safe (std::mac-issue..) clear beforehand
56 		}
57 
58 		//the one to use
NodeNode59 		Node(std::string _key, std::string _value, std::string _comment) {
60 			this->key = _key;
61 			this->value = _value;
62 			this->comment = _comment;
63 			children.clear();
64 		}
65 	};
66 
67 	// the map (always alphabetic) to collect key-value pairs
68 	// - Node* rather than string to have access to value and comment info
69 	typedef std::map<std::string,Node*> TagMap;
70 	TagMap tagMap;
71 
72 	//used for changeValue and addComment
73 	//(NB: not null-ed or such on push+pop, thus stretches beyond)
74 	Node* lastNode;
75 
76 	//we need a stack to iterate in and out
77 	// during build-up and dump recursion
78 	typedef std::list<Node*> NodeStack;
79 
80 	NodeStack nodeStack;
81 	Node rootNode; //TODO: ("root","");
82 
83 	// control verbosity to ease debugging:
84 	static bool verbose;
85 
86 public:
87 	TagTree();
88 	~TagTree();
89 
90 	void reset();
91 
92 	// verbosity control (mute by default ) ===================================
93 	void setMute();
94 	void setVerbose();
95 
96 	//input functions =========================================================
97 
98 	void pushNode(const std::string key);
99 	void pushNode(const char* format, ...);
100 
101 	// add file offset as comment -> own routine to better output 64 bit offsets...
102 	void addOffset(LFA_FileRef file);
103 
104 	void popNode();
105 	void popAllNodes();
106 
107 	//sets a key-value pair and optinal comment. value is also optional and may be set at a later time
108 	//can also be used to set pure, standalone comments (using key==value=="")
109 	void setKeyValue(const std::string key,const std::string value="", const std::string comment="");
110 
111 	//updates the value of key without creating new key, value pairs.
112 	void updateKeyValue ( const std::string key, const std::string value, const std::string comment = "" );
113 
114 	// convenience functions //////////////////////////////////////////////////////////////////
115 	// these functions read bytes (assert in file-length), dump them to screen (as hex or as number)
116 	// and optionally return the values for further processing
117 
118 	//read, convert endianess, dump certain values all in one go:
119 	// * key - may be NULL if you just want to obtain the values but not make a KV entry
120 	// * returnValue - returns the bytes digested
121 	// * numOfBytes - 0-byte requests *are* legitimate, as they may reduce codeforks for the client
122 	void digest(LFA_FileRef file,const std::string key="",
123 							void* returnValue=NULL,
124 							XMP_Int32 numOfBytes=0);
125 
126 	////////////////////////////////////////////////////////////////////////////////////
127 	// numeric digest routines
128 	//
129 	// same parameters as above, plus:
130 	// * bigEndian -  set to false, if the number is in the file as little endian
131 	//                ( correct return value according to machine type is taken care of for either setting)
132 	// overload signed and unsigned, 32 and 16 bit
133 	// Note, again: key may be NULL if you just want to obtain the values but not make a KV entry
134 	XMP_Int64 digest64s(LFA_FileRef file,const std::string key="", bool BigEndian=false);
135 	XMP_Uns64 digest64u(LFA_FileRef file,const std::string key="", bool BigEndian=false,bool hexDisplay=false);
136 	XMP_Int32 digest32s(LFA_FileRef file,const std::string key="", bool BigEndian=false);
137 	XMP_Uns32 digest32u(LFA_FileRef file,const std::string key="", bool BigEndian=false,bool hexDisplay=false);
138 	XMP_Int16 digest16s(LFA_FileRef file,const std::string key="", bool BigEndian=false);
139 	XMP_Uns16 digest16u(LFA_FileRef file,const std::string key="", bool BigEndian=false,bool hexDisplay=false);
140 
141 	// "expected" Overrides
142 	void digest64s(XMP_Int64 expected, LFA_FileRef file,const std::string key="", bool BigEndian=false);
143 	void digest64u(XMP_Uns64 expected, LFA_FileRef file,const std::string key="", bool BigEndian=false,bool hexDisplay=false);
144 	void digest32s(XMP_Int32 expected, LFA_FileRef file,const std::string key="", bool BigEndian=false);
145 	void digest32u(XMP_Uns32 expected, LFA_FileRef file,const std::string key="", bool BigEndian=false,bool hexDisplay=false);
146 	void digest16s(XMP_Int16 expected, LFA_FileRef file,const std::string key="", bool BigEndian=false);
147 	void digest16u(XMP_Uns16 expected, LFA_FileRef file,const std::string key="", bool BigEndian=false,bool hexDisplay=false);
148 
149 	//CBR Overrides
150 	void digest64s(XMP_Int64* returnValue, LFA_FileRef file,const std::string key="", bool BigEndian=false);
151 	void digest64u(XMP_Uns64* returnValue, LFA_FileRef file,const std::string key="", bool BigEndian=false,bool hexDisplay=false);
152 	void digest32s(XMP_Int32* returnValue, LFA_FileRef file,const std::string key="", bool BigEndian=false);
153 	void digest32u(XMP_Uns32* returnValue, LFA_FileRef file,const std::string key="", bool BigEndian=false,bool hexDisplay=false);
154 	void digest16s(XMP_Int16* returnValue, LFA_FileRef file,const std::string key="", bool BigEndian=false);
155 	void digest16u(XMP_Uns16* returnValue, LFA_FileRef file,const std::string key="", bool BigEndian=false,bool hexDisplay=false);
156 
157 
158 	//8-bit string (whichever encoding -> "buginese") to std::string
159 	//use length==0 to indicate zero-termination,
160 	//otherwise indicated lenght will be grabbed also accross \0 's
161 	//(length is counted w/o trailing zero termination, i.e. length("hans")==4 )
162 	// TODO: length default = 0 not yet implemented
163 	// verifyZeroTerm
164 	//  - has an effect only if a length!=0 is given (otherwise things go up to the 0 anyway)
165 	//  - in this case, asserts that the string has a terminating zero
166 	//   (_after_ <length> bytes, otherwise that byte is not read which has an impact on the filepointer!)
167 	//    would throw if any zero (\0) is encountered prior to that
168 	std::string digestString(LFA_FileRef file,const std::string key="", size_t length=0, bool verifyZeroTerm=false, bool allowEarlyZeroTerm=false );
169 
170 	// (wrappers)
171 	// standalone comment
172 	void comment(const std::string comment);
173 	// standalone comment
174 	// be aware of bug1741056, feeding 64bit numbers might not output correctly
175 	void comment(const char* format, ...);
176 
177 	//sometimes its worth changing (or actually setting for the first time) they current
178 	//(aka last set) key/value at a later time. includes correction in tagmap.
179 	void changeValue(const std::string value);
180 	void changeValue(const char* format, ...);
181 
182 	//adds a comment to last prior entry ( which could be KeyValue, Node or standalone comment...)
183 	void addComment(const std::string comment);
184 	//adds a comment to last prior entry ( which could be KeyValue, Node or standalone comment...)
185 	void addComment(const char* format, ...);
186 
187 	//output functions ===========================================================
188 	void dumpTree(bool commentsFlag=true, Node* pNode = NULL,unsigned int depth=0);
189 
190 	void dumpTagMap();
191 	void dumpTagList(Node* pNode = NULL,unsigned int depth=0);
192 
193 	std::string getValue(const std::string key);
194 	std::string getComment(const std::string key);
195 	unsigned int getSubNodePos( const std::string nodeKey, const std::string parentKey = "", int skip = 0 );
196 	XMP_Int64 getNodeSize( const std::string nodeKey );
197 
198 	//returns true if there is such a node, false if not, error if it happens to be key-value pair
199 	bool hasNode(const std::string key);
200 	XMP_Int32 getNodeCount(const std::string key);
201 };
202 
203 #endif
204