1/* libs/graphics/views/SkMetaData.cpp
2**
3** Copyright 2006, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9**     http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18#include "SkMetaData.h"
19
20SkMetaData::SkMetaData() : fRec(NULL)
21{
22}
23
24SkMetaData::SkMetaData(const SkMetaData& src) : fRec(NULL)
25{
26    *this = src;
27}
28
29SkMetaData::~SkMetaData()
30{
31    this->reset();
32}
33
34void SkMetaData::reset()
35{
36    Rec* rec = fRec;
37    while (rec)
38    {
39        Rec* next = rec->fNext;
40        Rec::Free(rec);
41        rec = next;
42    }
43    fRec = NULL;
44}
45
46SkMetaData& SkMetaData::operator=(const SkMetaData& src)
47{
48    this->reset();
49
50    const Rec* rec = src.fRec;
51    while (rec)
52    {
53        this->set(rec->name(), rec->data(), rec->fDataLen, (Type)rec->fType, rec->fDataCount);
54        rec = rec->fNext;
55    }
56    return *this;
57}
58
59void SkMetaData::setS32(const char name[], int32_t value)
60{
61    (void)this->set(name, &value, sizeof(int32_t), kS32_Type, 1);
62}
63
64void SkMetaData::setScalar(const char name[], SkScalar value)
65{
66    (void)this->set(name, &value, sizeof(SkScalar), kScalar_Type, 1);
67}
68
69SkScalar* SkMetaData::setScalars(const char name[], int count, const SkScalar values[])
70{
71    SkASSERT(count > 0);
72    if (count > 0)
73        return (SkScalar*)this->set(name, values, sizeof(SkScalar), kScalar_Type, count);
74    return NULL;
75}
76
77void SkMetaData::setString(const char name[], const char value[])
78{
79    (void)this->set(name, value, sizeof(char), kString_Type, strlen(value) + 1);
80}
81
82void SkMetaData::setPtr(const char name[], void* ptr)
83{
84    (void)this->set(name, &ptr, sizeof(void*), kPtr_Type, 1);
85}
86
87void SkMetaData::setBool(const char name[], bool value)
88{
89    (void)this->set(name, &value, sizeof(bool), kBool_Type, 1);
90}
91
92void* SkMetaData::set(const char name[], const void* data, size_t dataSize, Type type, int count)
93{
94    SkASSERT(name);
95    SkASSERT(dataSize);
96    SkASSERT(count > 0);
97
98    (void)this->remove(name, type);
99
100    size_t  len = strlen(name);
101    Rec*    rec = Rec::Alloc(sizeof(Rec) + dataSize * count + len + 1);
102
103#ifndef SK_DEBUG
104    rec->fType = SkToU8(type);
105#else
106    rec->fType = type;
107#endif
108    rec->fDataLen = SkToU8(dataSize);
109    rec->fDataCount = SkToU16(count);
110    if (data)
111        memcpy(rec->data(), data, dataSize * count);
112    memcpy(rec->name(), name, len + 1);
113
114#ifdef SK_DEBUG
115    rec->fName = rec->name();
116    switch (type) {
117    case kS32_Type:
118        rec->fData.fS32 = *(const int32_t*)rec->data();
119        break;
120    case kScalar_Type:
121        rec->fData.fScalar = *(const SkScalar*)rec->data();
122        break;
123    case kString_Type:
124        rec->fData.fString = (const char*)rec->data();
125        break;
126    case kPtr_Type:
127        rec->fData.fPtr = *(void**)rec->data();
128        break;
129    case kBool_Type:
130        rec->fData.fBool = *(const bool*)rec->data();
131        break;
132    default:
133        SkASSERT(!"bad type");
134        break;
135    }
136#endif
137
138    rec->fNext = fRec;
139    fRec = rec;
140    return rec->data();
141}
142
143bool SkMetaData::findS32(const char name[], int32_t* value) const
144{
145    const Rec* rec = this->find(name, kS32_Type);
146    if (rec)
147    {
148        SkASSERT(rec->fDataCount == 1);
149        if (value)
150            *value = *(const int32_t*)rec->data();
151        return true;
152    }
153    return false;
154}
155
156bool SkMetaData::findScalar(const char name[], SkScalar* value) const
157{
158    const Rec* rec = this->find(name, kScalar_Type);
159    if (rec)
160    {
161        SkASSERT(rec->fDataCount == 1);
162        if (value)
163            *value = *(const SkScalar*)rec->data();
164        return true;
165    }
166    return false;
167}
168
169const SkScalar* SkMetaData::findScalars(const char name[], int* count, SkScalar values[]) const
170{
171    const Rec* rec = this->find(name, kScalar_Type);
172    if (rec)
173    {
174        if (count)
175            *count = rec->fDataCount;
176        if (values)
177            memcpy(values, rec->data(), rec->fDataCount * rec->fDataLen);
178        return (const SkScalar*)rec->data();
179    }
180    return NULL;
181}
182
183bool SkMetaData::findPtr(const char name[], void** value) const
184{
185    const Rec* rec = this->find(name, kPtr_Type);
186    if (rec)
187    {
188        SkASSERT(rec->fDataCount == 1);
189        if (value)
190            *value = *(void**)rec->data();
191        return true;
192    }
193    return false;
194}
195
196const char* SkMetaData::findString(const char name[]) const
197{
198    const Rec* rec = this->find(name, kString_Type);
199    SkASSERT(rec == NULL || rec->fDataLen == sizeof(char));
200    return rec ? (const char*)rec->data() : NULL;
201}
202
203bool SkMetaData::findBool(const char name[], bool* value) const
204{
205    const Rec* rec = this->find(name, kBool_Type);
206    if (rec)
207    {
208        SkASSERT(rec->fDataCount == 1);
209        if (value)
210            *value = *(const bool*)rec->data();
211        return true;
212    }
213    return false;
214}
215
216const SkMetaData::Rec* SkMetaData::find(const char name[], Type type) const
217{
218    const Rec* rec = fRec;
219    while (rec)
220    {
221        if (rec->fType == type && !strcmp(rec->name(), name))
222            return rec;
223        rec = rec->fNext;
224    }
225    return NULL;
226}
227
228bool SkMetaData::remove(const char name[], Type type)
229{
230    Rec* rec = fRec;
231    Rec* prev = NULL;
232    while (rec)
233    {
234        Rec* next = rec->fNext;
235        if (rec->fType == type && !strcmp(rec->name(), name))
236        {
237            if (prev)
238                prev->fNext = next;
239            else
240                fRec = next;
241            Rec::Free(rec);
242            return true;
243        }
244        prev = rec;
245        rec = next;
246    }
247    return false;
248}
249
250bool SkMetaData::removeS32(const char name[])
251{
252    return this->remove(name, kS32_Type);
253}
254
255bool SkMetaData::removeScalar(const char name[])
256{
257    return this->remove(name, kScalar_Type);
258}
259
260bool SkMetaData::removeString(const char name[])
261{
262    return this->remove(name, kString_Type);
263}
264
265bool SkMetaData::removePtr(const char name[])
266{
267    return this->remove(name, kPtr_Type);
268}
269
270bool SkMetaData::removeBool(const char name[])
271{
272    return this->remove(name, kBool_Type);
273}
274
275///////////////////////////////////////////////////////////////////////////////////
276
277SkMetaData::Iter::Iter(const SkMetaData& metadata)
278{
279    fRec = metadata.fRec;
280}
281
282void SkMetaData::Iter::reset(const SkMetaData& metadata)
283{
284    fRec = metadata.fRec;
285}
286
287const char* SkMetaData::Iter::next(SkMetaData::Type* t, int* count)
288{
289    const char* name = NULL;
290
291    if (fRec)
292    {
293        if (t)
294            *t = (SkMetaData::Type)fRec->fType;
295        if (count)
296            *count = fRec->fDataCount;
297        name = fRec->name();
298
299        fRec = fRec->fNext;
300    }
301    return name;
302}
303
304///////////////////////////////////////////////////////////////////////////////////
305
306SkMetaData::Rec* SkMetaData::Rec::Alloc(size_t size)
307{
308    return (Rec*)sk_malloc_throw(size);
309}
310
311void SkMetaData::Rec::Free(Rec* rec)
312{
313    sk_free(rec);
314}
315
316///////////////////////////////////////////////////////////////////////////////////
317///////////////////////////////////////////////////////////////////////////////////
318
319#ifdef SK_DEBUG
320
321void SkMetaData::UnitTest()
322{
323#ifdef SK_SUPPORT_UNITTEST
324    SkMetaData  m1;
325
326    SkASSERT(!m1.findS32("int"));
327    SkASSERT(!m1.findScalar("scalar"));
328    SkASSERT(!m1.findString("hello"));
329    SkASSERT(!m1.removeS32("int"));
330    SkASSERT(!m1.removeScalar("scalar"));
331    SkASSERT(!m1.removeString("hello"));
332    SkASSERT(!m1.removeString("true"));
333    SkASSERT(!m1.removeString("false"));
334
335    m1.setS32("int", 12345);
336    m1.setScalar("scalar", SK_Scalar1 * 42);
337    m1.setString("hello", "world");
338    m1.setPtr("ptr", &m1);
339    m1.setBool("true", true);
340    m1.setBool("false", false);
341
342    int32_t     n;
343    SkScalar    s;
344
345    m1.setScalar("scalar", SK_Scalar1/2);
346
347    SkASSERT(m1.findS32("int", &n) && n == 12345);
348    SkASSERT(m1.findScalar("scalar", &s) && s == SK_Scalar1/2);
349    SkASSERT(!strcmp(m1.findString("hello"), "world"));
350    SkASSERT(m1.hasBool("true", true));
351    SkASSERT(m1.hasBool("false", false));
352
353    Iter    iter(m1);
354    const char* name;
355
356    static const struct {
357        const char*         fName;
358        SkMetaData::Type    fType;
359        int                 fCount;
360    } gElems[] = {
361        { "int",    SkMetaData::kS32_Type,      1 },
362        { "scalar", SkMetaData::kScalar_Type,   1 },
363        { "ptr",    SkMetaData::kPtr_Type,      1 },
364        { "hello",  SkMetaData::kString_Type,   sizeof("world") },
365        { "true",   SkMetaData::kBool_Type,     1 },
366        { "false",  SkMetaData::kBool_Type,     1 }
367    };
368
369    int                 loop = 0;
370    int count;
371    SkMetaData::Type    t;
372    while ((name = iter.next(&t, &count)) != NULL)
373    {
374        int match = 0;
375        for (unsigned i = 0; i < SK_ARRAY_COUNT(gElems); i++)
376        {
377            if (!strcmp(name, gElems[i].fName))
378            {
379                match += 1;
380                SkASSERT(gElems[i].fType == t);
381                SkASSERT(gElems[i].fCount == count);
382            }
383        }
384        SkASSERT(match == 1);
385        loop += 1;
386    }
387    SkASSERT(loop == SK_ARRAY_COUNT(gElems));
388
389    SkASSERT(m1.removeS32("int"));
390    SkASSERT(m1.removeScalar("scalar"));
391    SkASSERT(m1.removeString("hello"));
392    SkASSERT(m1.removeBool("true"));
393    SkASSERT(m1.removeBool("false"));
394
395    SkASSERT(!m1.findS32("int"));
396    SkASSERT(!m1.findScalar("scalar"));
397    SkASSERT(!m1.findString("hello"));
398    SkASSERT(!m1.findBool("true"));
399    SkASSERT(!m1.findBool("false"));
400#endif
401}
402
403#endif
404
405
406