michael@0: // Copyright (c) 2007, Google Inc. michael@0: // All rights reserved. michael@0: // michael@0: // Redistribution and use in source and binary forms, with or without michael@0: // modification, are permitted provided that the following conditions are michael@0: // met: michael@0: // michael@0: // * Redistributions of source code must retain the above copyright michael@0: // notice, this list of conditions and the following disclaimer. michael@0: // * Redistributions in binary form must reproduce the above michael@0: // copyright notice, this list of conditions and the following disclaimer michael@0: // in the documentation and/or other materials provided with the michael@0: // distribution. michael@0: // * Neither the name of Google Inc. nor the names of its michael@0: // contributors may be used to endorse or promote products derived from michael@0: // this software without specific prior written permission. michael@0: // michael@0: // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS michael@0: // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT michael@0: // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR michael@0: // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT michael@0: // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, michael@0: // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT michael@0: // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, michael@0: // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY michael@0: // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT michael@0: // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE michael@0: // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. michael@0: // michael@0: // SimpleStringDictionary.h michael@0: // michael@0: michael@0: #ifndef SimpleStringDictionary_H__ michael@0: #define SimpleStringDictionary_H__ michael@0: michael@0: #import michael@0: #import michael@0: michael@0: namespace google_breakpad { michael@0: michael@0: //============================================================================== michael@0: // SimpleStringDictionary (and associated class KeyValueEntry) implement a very michael@0: // basic dictionary container class. It has the property of not making any michael@0: // memory allocations when getting and setting values. But it is not very michael@0: // efficient, with calls to get and set values operating in linear time. michael@0: // It has the additional limitation of having a fairly small fixed capacity of michael@0: // SimpleStringDictionary::MAX_NUM_ENTRIES entries. An assert() will fire if michael@0: // the client attempts to set more than this number of key/value pairs. michael@0: // Ordinarilly a C++ programmer would use something like the std::map template michael@0: // class, or on the Macintosh would often choose CFDictionary or NSDictionary. michael@0: // But these dictionary classes may call malloc() during get and set operations. michael@0: // Google Breakpad requires that no memory allocations be made in code running michael@0: // in its exception handling thread, so it uses SimpleStringDictionary as the michael@0: // underlying implementation for the GoogleBreakpad.framework APIs: michael@0: // GoogleBreakpadSetKeyValue(), GoogleBreakpadKeyValue(), and michael@0: // GoogleBreakpadRemoveKeyValue() michael@0: // michael@0: michael@0: //============================================================================== michael@0: // KeyValueEntry michael@0: // michael@0: // A helper class used by SimpleStringDictionary representing a single michael@0: // storage cell for a key/value pair. Each key and value string are michael@0: // limited to MAX_STRING_STORAGE_SIZE-1 bytes (not glyphs). This class michael@0: // performs no memory allocations. It has methods for setting and getting michael@0: // key and value strings. michael@0: // michael@0: class KeyValueEntry { michael@0: public: michael@0: KeyValueEntry() { michael@0: Clear(); michael@0: } michael@0: michael@0: KeyValueEntry(const char *key, const char *value) { michael@0: SetKeyValue(key, value); michael@0: } michael@0: michael@0: void SetKeyValue(const char *key, const char *value) { michael@0: if (!key) { michael@0: key = ""; michael@0: } michael@0: if (!value) { michael@0: value = ""; michael@0: } michael@0: michael@0: strlcpy(key_, key, sizeof(key_)); michael@0: strlcpy(value_, value, sizeof(value_)); michael@0: } michael@0: michael@0: void SetValue(const char *value) { michael@0: if (!value) { michael@0: value = ""; michael@0: } michael@0: strlcpy(value_, value, sizeof(value_)); michael@0: }; michael@0: michael@0: // Removes the key/value michael@0: void Clear() { michael@0: memset(key_, 0, sizeof(key_)); michael@0: memset(value_, 0, sizeof(value_)); michael@0: } michael@0: michael@0: bool IsActive() const { return key_[0] != '\0'; } michael@0: const char *GetKey() const { return key_; } michael@0: const char *GetValue() const { return value_; } michael@0: michael@0: // Don't change this without considering the fixed size michael@0: // of MachMessage (in MachIPC.h) michael@0: // (see also struct KeyValueMessageData in Inspector.h) michael@0: enum {MAX_STRING_STORAGE_SIZE = 256}; michael@0: michael@0: private: michael@0: char key_[MAX_STRING_STORAGE_SIZE]; michael@0: char value_[MAX_STRING_STORAGE_SIZE]; michael@0: }; michael@0: michael@0: //============================================================================== michael@0: // This class is not an efficient dictionary, but for the purposes of breakpad michael@0: // will be just fine. We're just dealing with ten or so distinct michael@0: // key/value pairs. The idea is to avoid any malloc() or free() calls michael@0: // in certain important methods to be called when a process is in a michael@0: // crashed state. Each key and value string are limited to michael@0: // KeyValueEntry::MAX_STRING_STORAGE_SIZE-1 bytes (not glyphs). Strings passed michael@0: // in exceeding this length will be truncated. michael@0: // michael@0: class SimpleStringDictionary { michael@0: public: michael@0: SimpleStringDictionary() {}; // entries will all be cleared michael@0: michael@0: // Returns the number of active key/value pairs. The upper limit for this michael@0: // is MAX_NUM_ENTRIES. michael@0: int GetCount() const; michael@0: michael@0: // Given |key|, returns its corresponding |value|. michael@0: // If |key| is NULL, an assert will fire or NULL will be returned. If |key| michael@0: // is not found or is an empty string, NULL is returned. michael@0: const char *GetValueForKey(const char *key) const; michael@0: michael@0: // Stores a string |value| represented by |key|. If |key| is NULL or an empty michael@0: // string, this will assert (or do nothing). If |value| is NULL then michael@0: // the |key| will be removed. An empty string is OK for |value|. michael@0: void SetKeyValue(const char *key, const char *value); michael@0: michael@0: // Given |key|, removes any associated value. It will assert (or do nothing) michael@0: // if NULL is passed in. It will do nothing if |key| is not found. michael@0: void RemoveKey(const char *key); michael@0: michael@0: // This is the maximum number of key/value pairs which may be set in the michael@0: // dictionary. An assert may fire if more values than this are set. michael@0: // Don't change this without also changing comment in GoogleBreakpad.h michael@0: enum {MAX_NUM_ENTRIES = 64}; michael@0: michael@0: private: michael@0: friend class SimpleStringDictionaryIterator; michael@0: michael@0: const KeyValueEntry *GetEntry(int i) const; michael@0: michael@0: KeyValueEntry entries_[MAX_NUM_ENTRIES]; michael@0: }; michael@0: michael@0: //============================================================================== michael@0: class SimpleStringDictionaryIterator { michael@0: public: michael@0: SimpleStringDictionaryIterator(const SimpleStringDictionary &dict) michael@0: : dict_(dict), i_(0) { michael@0: } michael@0: michael@0: // Initializes iterator to the beginning (may later call Next() ) michael@0: void Start() { michael@0: i_ = 0; michael@0: } michael@0: michael@0: // like the nextObject method of NSEnumerator (in Cocoa) michael@0: // returns NULL when there are no more entries michael@0: // michael@0: const KeyValueEntry* Next() { michael@0: for (; i_ < SimpleStringDictionary::MAX_NUM_ENTRIES; ++i_) { michael@0: const KeyValueEntry *entry = dict_.GetEntry(i_); michael@0: if (entry->IsActive()) { michael@0: i_++; // move to next entry for next time michael@0: return entry; michael@0: } michael@0: } michael@0: michael@0: return NULL; // reached end of array michael@0: } michael@0: michael@0: private: michael@0: const SimpleStringDictionary& dict_; michael@0: int i_; michael@0: }; michael@0: michael@0: } // namespace google_breakpad michael@0: michael@0: #endif // SimpleStringDictionary_H__